Odwrócenie wielowymiarowe


23

Biorąc pod uwagę N-wymiarową ortogonalną (niewyrównaną) tablicę liczb całkowitych nieujemnych oraz wskazanie, które wymiary należy odwrócić, zwróć tablicę, ale odwróci się wzdłuż tych wymiarów. Wskazanie może być podane jako logiczna lista długości N lub lista podzbioru pierwszych N wymiarów indeksowanych od 0 lub 1.

Proszę podać formaty wejściowe. Wyjaśnienia kodu są bardzo mile widziane.

Przykład przejścia

Otrzymujemy 2-warstwowy 3-rzędowy 4-kolumnowy układ 3D

[[[ 1, 2, 3, 4],
  [ 5, 6, 7, 8],
  [ 9,10,11,12]],

 [[13,14,15,16],
  [17,18,19,20],
  [21,22,23,24]]]

i jeden z

[true,false,true](Lista boolowska)
[0,2]( lista 0-indeksowana)
[1,3]( lista 1-indeksowana)

Musimy odwrócić kolejność pierwszego i ostatniego wymiaru, czyli warstw i elementów wierszy (kolumn), ale nie wierszy każdej warstwy. Po pierwsze (faktyczna kolejność, w jakiej to robisz, nie ma znaczenia) odwracamy kolejność warstw:

[[[13,14,15,16],
  [17,18,19,20],
  [21,22,23,24]],

 [[ 1, 2, 3, 4],
  [ 5, 6, 7, 8],
  [ 9,10,11,12]]]

a następnie odwracamy kolejność elementów każdego wiersza:

[[[16,15,14,13],
  [20,19,18,17],
  [24,23,22,21]],

 [[ 4, 3, 2, 1],
  [ 8, 7, 6, 5],
  [12,11,10, 9]]]

Przypadki testowe

[[[1,2,3,4],[5,6,7,8],[9,10,11,12]],[[13,14,15,16],[17,18,19,20],[21,22,23,24]]]
[true,false,true]/ [0,2]/ [1,3]
 ↓ 
[[[16,15,14,13],[20,19,18,17],[24,23,22,21]],[[4,3,2,1],[8,7,6,5],[12,11,10,9]]]


[[1,2,3],[4,5,6]]
[true,false]/ [0]/ [1]
 ↓
[[4,5,6],[1,2,3]]


[[1],[4]]
[true,false]/ [0]/ [1]
 ↓
[[4],[1]]


[[7]]
[true,true]/ [0,1]/ [1,2]
 ↓
[[7]]


[1,2,3,4,5,6,7]
[true]/ [0]/ [1]
 ↓
[7,6,5,4,3,2,1]


[]
[true]/ [0]/ [1]
 ↓
[]


[[],[]]
[false,false]/ []/ []
 ↓
[[],[]]


[[[[3,1,4,1],[5,9,2,6]],[[5,3,5,8],[9,7,9,3]]],[[[2,3,8,4],[6,2,6,4]],[[3,3,8,3],[2,7,9,5]]]]
[true,false,true,true]/ [0,2,3]/ [1,3,4]
 ↓
[[[[4,6,2,6],[4,8,3,2]],[[5,9,7,2],[3,8,3,3]]],[[[6,2,9,5],[1,4,1,3]],[[3,9,7,9],[8,5,3,5]]]]


[[[[3,1,4,1],[5,9,2,6]],[[5,3,5,8],[9,7,9,3]]],[[[2,3,8,4],[6,2,6,4]],[[3,3,8,3],[2,7,9,5]]]]
[false,true,false,false]/ [1]/ [2]
 ↓
[[[[5,3,5,8],[9,7,9,3]],[[3,1,4,1],[5,9,2,6]]],[[[3,3,8,3],[2,7,9,5]],[[2,3,8,4],[6,2,6,4]]]]


[[[[3,1,4,1],[5,9,2,6]],[[5,3,5,8],[9,7,9,3]]],[[[2,3,8,4],[6,2,6,4]],[[3,3,8,3],[2,7,9,5]]]]
[false,false,false,false]/ []/ []
 ↓
[[[[3,1,4,1],[5,9,2,6]],[[5,3,5,8],[9,7,9,3]]],[[[2,3,8,4],[6,2,6,4]],[[3,3,8,3],[2,7,9,5]]]]


Wydaje mi się, że najtrudniejszą częścią w większości statycznie typowanych języków będzie gra w golfa z podpisami.
Οurous

@ Οurous Jak te języki zwykle radzą sobie z dowolnymi danymi tablicowymi?
Adám

1
są trzy przypadki użycia „normalnego”, tak jak ja to widzę: martwienie się tylko o jeden poziom tablicy (np .: reversedziała na dowolnych tablicach, ale zależy tylko na pierwszym poziomie), ogólne lub klasy rekurencyjne (klasy typu / obiektu w zależności od funkcjonalności lub OOP, ale podobny przypadek użycia). Te dwa ostatnie są zwykle bardziej szczegółowe.
Οurous

Czy możemy przechowywać macierz jako tablice wskaźników do wskaźników (w C lub asm), zamiast odpowiednich tablic wielowymiarowych, w których wszystko jest ciągłe w pamięci? Jestem prawie pewien, że wszystkie normalne języki o wyższym poziomie / dynamicznym pisaniu z arbitralnym zagnieżdżaniem list już traktują rzeczy jak listy, a nie macierze, więc założę, że jest w porządku.
Peter Cordes,

@PeterCordes Pewnie, śmiało.
Adám

Odpowiedzi:


8

APL (Dyalog) , 20 9 bajtów

⊃{⌽[⍺]⍵}/

Wypróbuj online!

W jaki sposób?

/ - zmniejsz - weź element znajdujący się najbardziej na prawo w wejściu (tablicę) i zastosuj funkcję z następnym lewym elementem jako lewym argumentem

{⌽[⍺]⍵}- odwróć w left argument( wymiarze )

- spłaszczyć załączoną tablicę



8

JavaScript (Node.js) , 58 55 53 45 bajtów

Zaoszczędź 8 bajtów dzięki @Shaggy

Pobiera dane wejściowe jako (indications)(array), gdzie wskazaniami jest lista boolowska.

f=([r,...b])=>a=>1/r?a.sort(_=>r).map(f(b)):a

Wypróbuj online!

Skomentował

f = (                // f is a function taking:
  [r,                //   r = next 'reverse' Boolean flag
      ...b]          //   b = array of remaining flags
) =>                 // and returning an anonymous function taking:
  a =>               //   a = array (or sub-array) to process, or atomic element
    1 / r ?          // if r is defined:
      a.sort(_ => r) //   reverse a if r = 1; leave it unchanged otherwise
      .map(f(b))     //   for each element in the resulting array: do a recursive call,
                     //   using f to generate a new callback function for the next flag
    :                // else:
      a              //   a must be an atomic element and is simply left unchanged

Wydaje się, że samo używanie rzamiast miejsca r||-1 wydaje się działać .
Shaggy

Czy f=([r,...b])=>a=>1/r?a.sort(_=>r).map(f(b)):azadziała? Na moim telefonie nie mogę poprawnie przetestować.
Shaggy

@Shaggy Nice! Podoba mi się ten dość nietypowy przebieg przetwarzania.
Arnauld


5

Galaretka , 8 bajtów

”€ẋ”ṚpFv

Pobiera indeksowaną listę 0 wymiarów.

Wypróbuj online!

Jak to działa

”€ẋ”ṚpFv  Main link. Left arg: D (dimensions, 0-based), Right arg: A (array)

”€ẋ       Repeat '€' d times, for each d in D.
   ”Ṛp    Perform Cartesian product of ['Ṛ'] and each string of '€'s, prepending a
          'Ṛ' to each string of '€'s.
      F   Flatten the result.
          If, e.g., D = [0,2,4], we build the string "ṚṚ€€Ṛ€€€€".
       v  Eval the resulting string, using A as left argument.

1
To okropne. Bardzo dobrze!
Adám

5

R , 80 78 77 bajtów

Utwórz wywołanie do ekstraktora R, [tworząc listę sekwencji odwróconych tam, gdzie jest to wskazane. W rzeczywistości zawierają zera, które są dyskretnie ignorowane. Jest drop=Fto konieczne, aby zapobiec domyślnemu upuszczaniu wymiarów R. Potrzebujemyrev wywołania do odwrotnego wskaźnika wymiaru, ponieważ R wypełnia tablice.

-2 dzięki @Giuseppe

-1 przy użyciu przypisania liniowego.

function(x,a,d=dim(x))do.call("[",c(list(x),Map(seq,r<-d*rev(a),d-r),drop=F))

Wypróbuj online!

Wyróżnienie dla @JayCe, który wymyślił odmianę, która uzyskuje ten sam wynik w tej samej długości:

function(x,a,d=dim(x))array(x[t(t(expand.grid(Map(seq,r<-d*rev(a),d-r))))],d)

Wypróbuj online!


1
78 bajtów bardzo ładna odpowiedź!
Giuseppe,

1
Bardzo głęboka odpowiedź. Zajęło mi trochę czasu, aby całkowicie to zrozumieć. Próbowałem replikować go bez użycia do.call- ma on więcej niż 83 bajty, wciąż zamieszczając to tutaj jako komentarz w celach informacyjnych: TIO
JayCe

Cóż, właściwie, @JayCe, twoją świetną odpowiedź można również rozegrać w golfa do 78 bajtów!
J.Doe

5

Haskell, 120 119 bajtów

funkcja f przyjmuje jako dane wejściową listę N-wymiarową i listę bool

class F r where f::[Bool]->r->r
instance F Int where f=seq
instance F r=>F[r]where f(a:y)=last(id:[reverse|a]).map(f y)

1
Nie potrzebujesz nawiasów F r.
Ørjan Johansen

1
Łącze TIO z testami i 1-bajtowym golfem OJ.
Khuldraeseth na'Barya

4

05AB1E , 23 11 10 bajtów

'€s×'R«J.V

Wypróbuj online.

-12 bajtów dzięki @ Mr.Xcoder .

Wprowadź jako indeksowane wartości 0 (tj. [0,2,3]), Które są pierwszym wejściem.

Wyjaśnienie:

'€s×           # Repeat "€" the indices amount of times
               #  i.e. [0,2,3] → ["","€€","€€€"]
    'R«        # Append each with "R"
               #  i.e. ["","€€","€€€"] → ["R","€€R","€€€R"]
        J      # Join them all together
               #  i.e. ["R","€€R","€€€R"] → R€€R€€€R
         .V    # Execute string as 05AB1E code

Na przykład: jeśli lista wejściowa indeksów to [0,2,3], utworzy następujący ciąg:

R€€R€€€R

Które będą:

    €€€R    # Reverse the items in the most inner (4th level) lists
 €€R        # Reverse the most inner (3rd level) lists themselves
            # Do nothing with the inner (2nd level) lists 
R           # Reverse the entire outer (1st level) list

Oryginalna 23 bajtowa odpowiedź:

ćURvy„ RèJ…εÿ}}„ RXèJ.V

Wprowadź jako listę boolean (tj. [1,0,1,1]), Która jest pierwszym wejściem.

Wypróbuj online.

Wyjaśnienie:

ćU                 # Pop and save the first boolean in variable `X`
  R                # Reverse the remaining boolean-list
   v    }          # Loop `y` over each of them:
     Rè           #  Take the string "R ", and index the current boolean (0 or 1) in it
    J              #  Join it together with the string of the previous iteration
    …εÿ}           #  Surround it with "ε" and "}"
          RXè     # Index variable `X` also in "R "
              J    # Join it together with the rest
.V                 # Execute string as 05AB1E code

Na przykład: jeśli boolowska lista wejściowa jest [1,0,1,1], utworzy następujący ciąg:

εεεR}R} }R

Które będą:

  εR}         # Reverse the items in the most inner (4th level) lists
 ε   R}       # Reverse the most inner (3rd level) lists themselves
ε       }     # Do nothing with the inner (2nd level) lists 
         R    # Reverse the entire outer (1st level) list

1
Dobra odpowiedź, ale ... uhm ... czy ten 11 bajterów zadziała?
Pan Xcoder,

@ Mr.Xcoder Thanks! To rzeczywiście o wiele łatwiejsze. I udało się zagrać w golfa o 1 bajt więcej, dodając każdy z nich, zamiast dodawać, a następnie cofać.
Kevin Cruijssen

@ Mr.Xcoder Btw, dlaczego 'x*działa powtarzanie xn razy bez użycia sWAP, ale nie działa z '€*? .. EDYCJA: Tylko w starszej wersji ...
Kevin Cruijssen

Starsza wersja jest dość błędna, może to wynikać z faktu, że nadal jest analizowana jako operator, nawet jeśli jest w literałach char? Nie jestem szczery. W nowej wersji *nie zachowuje się jednak tak samo.
Pan Xcoder,

3

JavaScript (Node.js) , 60 bajtów

Inne (rekurencyjne) podejście. nie bije odpowiedzi Arnaulda ... jeszcze ...

Przyjmuje dane wejściowe jako array, boolean list

f=(a,r)=>r>[]?(r[0]?a.reverse():a).map(c=>f(c,r.slice(1))):a

f=(a,r)=>r>[]?(r[0]?a.reverse():a).map(c=>f(c,r.slice(1))):a

console.log(f([[[[3,1,4,1],[5,9,2,6]],[[5,3,5,8],[9,7,9,3]]],[[[2,3,8,4],[6,2,6,4]],[[3,3,8,3],[2,7,9,5]]]],[true,false,true,true]))


3

Pyth , 15 bajtów

.v+jk.n*\_*L\ME

Wypróbuj tutaj!

Irytująco, obchodzenia się pusta lista wymiar sprawy nie mniej niż 2 bajtów zajmuje ... Wolę używać ssw miejscu jk.n, ale: | Zakłada, że ​​lista do transformacji może być podana w natywnej składni języka Pyth jako ciąg. Napisałem konwerter do składni Pyth, aby ułatwić testowanie. W niefortunnym przypadku, gdy OP zdecyduje się na to nie zezwalać, 17-bajtowy „naprawi” to:

.v+jk.n*\_*L\ME\E

3

Japt , 15 14 bajtów

Z pewną inspiracją z rozwiązania Arnauld .

Pobiera wskazania jako pierwsze wejście, jako boolowską tablicę 1s i 0s.

Ê?Vn@ÎãßUÅX:V

Spróbuj


Wyjaśnienie

                   :Implicit input of boolean array U=indications and multi-dimensional integer array V
Ê                  :Get the length of U
 ?                 :If truthy (i.e., >0)
  Vn               :  Sort V
    @ÎÃ            :   Function that gets the first element of U; 0 will leave the array untouched, 1 will reverse it.
       £           :  Map each X
        ß          :  Run the programme again with the following inputs
         UÅ        :   U with the first element removed
           X       :   X will serve as the new value of V
            :      :Else
             V     :  Just return V

3

Czysty , 122 112 bajtów

import StdEnv
class$r::[Bool]->r->r
instance$r where$_=id
instance$[r]| $r where$[a:y]=if(a)reverse id o map($y)

Wypróbuj online!

Wersja odpowiedzi Damiena Haskella, wykorzystująca system golfisty Clean'a. Naprawdę pokazuje duże podobieństwa między tymi dwoma językami.

Wyjaśnił:

import StdEnv                 // import basic stuff
class $ r :: [Bool] -> r -> r // $ takes a boolean list and returns a function on r to r
instance $ r                  // instance on all types, taken when no more specific instances exist
    where $ _ = id            // return the identity function for all arguments
instance $ [r] | $ r          // instance for lists of a type which has an instance itself
    where $ [a: y]
        = if(a) reverse id    // reverse if the head of the argument is true
            o map ($ y)       // composed with the map function acting on $ applied to the tail


1

(niesprawdzone, ale myślę poprawne. Wyjście asm kompilatora wygląda tak, jak się spodziewam. Zaktualizuje się, jeśli / kiedy znajdę czas na napisanie testowej wiązki, która tworzy i drukuje tę strukturę danych.)

GNU C ++ (przenośny) 148 bajtów

#include<algorithm>
#include<cstdint>
struct m{intptr_t d,l,a[];void R(int*r){if(*r)std::reverse(a,a+l);for(int i=0;d&&i<l;((m*)a[i++])->R(r+1));}};

GNU C ++ (int = wskaźnik i spada z nie-pustej funkcji UB) 120 bajtów

#include<algorithm>
struct m{int d,l,a[],R(int*r){if(*r)std::reverse(a,a+l);for(int i=0;d&&i<l;((m*)a[i++])->R(r+1));}};

Jest to struktura licznika głębokości, długości, tablicy {liczb całkowitych lub wskaźników}. Na dolnym poziomie tego niebinarnego drzewa ( depth==0) tablica intptr_tjest tablicą liczb całkowitych. Na wyższych poziomach jest struct m*przechowywany wintptr_t . Traversal bierze obsadę.

Funkcja R()odwrotna jest funkcją składową, ponieważ oszczędza to deklarowanie argumentu i wielep-> składni, aby odwoływać się do elementów struktury w porównaniu z domniemanymthis wskaźnika.

Jedynym rozszerzeniem GNU jest elastyczny element tablicy C99, który tworzy strukturę o zmiennej wielkości , który tworzy , która jest obsługiwana w C ++ jako rozszerzenie GNU. Mógłbym użyć *aelementu wskazującego na osobno przydzieloną tablicę i mieć to zwykły ISO C ++. (I to faktycznie zaoszczędziłoby bajt bez konieczności wprowadzania jakichkolwiek innych zmian). Napisałem to jako implementację makiety / referencji dla wersji asm.


Krótsza wersja z po prostu intdeklaruje również R()jako powracającąint zamiast void. Te dwa fragmenty hakerów nie są ze sobą powiązane; to tylko wersja „działa na co najmniej jednej implementacji”.

Powinien działać dobrze na 32-bitowych intobiektach docelowych (gdzie może zawierać wskaźnik), o ile kompilujesz z gcc7 lub starszym, lub wyłączasz optymalizacje. ( gcc8 -O3zakłada, że ​​wykonanie nie może dotrzeć do dolnej częścivoid niefunkcji, ponieważ byłby to UB). x86 gcc -m32 -O3powinien działać poprawnie z gcc7, jak na Godbolt gdzie obie wersje (w różnych przestrzeniach nazw) i wersję nie będącą funkcją członka .

Bez golfa

Funkcja arg, int r[]jest tablicą liczb całkowitych 0 / niezerowych, które wskazują, czy dana głębokość powinna zostać zamieniona, zaczynając od najbardziej zewnętrznego poziomu.

#include<algorithm>  // for std::reverse
#include<cstdint>    // for intptr_t.  GNU C defines __intptr_t, so we could use that...

struct m{
    __intptr_t d,l,a[];    // depth = 0 means values, >0 means pointers.
    // l = length
    //__intptr_t a[];  // flexible array member: array contiguous with the struct

    void R(int r[]) {
        if(*r)
            std::reverse(a, a+l);   // *r && std::reverse() doesn't work because it returns void.

        if(d) // recurse if this isn't the bottom depth
            for(int i=0 ; i<l ; i++)  // tree traversal
                ((m*)a[i])->R(r+1);   // with the rest of the depth list
    }

}; // struct m

Kiedy wracamy, mijamy r+1 , więc sprawdzanie bieżącej głębokości jest zawsze*r .

Wcześniejsza wersja przeszła rbez zmian i sprawdzona r[d]. Dzięki elastycznemu elementowi tablicy musiałem przechowywać jakiś wskaźnik ostatniego poziomu, ponieważ a[]nie jest wskaźnikiem, to prawdziwa tablica bez pośrednictwa. Ale zintptr_t *a członkiem nie mogłem tego po prostu miećnullptr na poziomie liścia, ponieważ chcę, żeby były to wartości.

Odwrócenie bieżącego poziomu przed lub po przejściu przez drzewo nie powinno mieć znaczenia. Nie próbowałem tego robić podczas .

Nie jestem pewien , czystd::reverse jest to warte liczenia bajtów w porównaniu z ręczną pętlą, zwłaszcza jeśli mogę zadzwonić R()do każdego wskaźnika dokładnie raz gdzieś w tej pętli. Ale tylko jeślid!=0


Zaraz, imponujące.
Adám

@ Adám: dzięki, grał w golfa zaskakująco naturalnie i dobrze po tym, jak to napisałem. Jestem ciekawy, co mogę zrobić w kodzie maszynowym x86: P
Peter Cordes,

1

Mathematica, 7 bajtów

Reverse

Funkcjonować. Daj mu zagnieżdżoną listę jako pierwszy argument, a opartą na 1 listę poziomów / wymiarów do odwrócenia jako drugi argument. Wypróbuj online!

Wreszcie, kolejne wyzwanie, w którym Mathematica ma wbudowane!


warstwy do odwrócenia ? Może link TIO?
Adám

@ Adám To znaczy lista wymiarów do odwrócenia, ogólnie określanych w Mathematica jako poziomy .
LegionMammal978,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.