Pembalikan multi-dimensi

23

Diberikan array ortogonal N-dimensional (non-compang-camping) dari bilangan bulat non-negatif, dan indikasi yang dimensi untuk membalik, mengembalikan array tetapi terbalik sepanjang dimensi tersebut. Indikasi dapat diberikan sebagai daftar panjang Boolean N atau daftar subset dari dimensi N pertama yang diindeks dari 0 atau 1.

Silakan sebutkan format input Anda. Penjelasan kode sangat dihargai.

Contoh walked-through

Kami diberi 2-layer 3-baris 4-kolom 3D-array

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

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

dan salah satunya

[true,false,true](Daftar Boolean)
[0,2]( daftar 0-diindeks)
[1,3]( daftar 1-diindeks)

Kita perlu membalik urutan dimensi pertama dan terakhir, yaitu lapisan dan elemen dari baris (kolom), tetapi bukan baris dari setiap lapisan. Pertama (urutan sebenarnya Anda melakukan ini tidak masalah) kami membalikkan urutan lapisan:

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

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

dan kemudian kita membalik urutan elemen dari setiap baris:

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

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

Uji kasus

[[[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]]]]

Adm
sumber
Saya merasa seperti bagian tersulit dalam sebagian besar bahasa yang diketik secara statis adalah bermain golf dengan jenis tanda tangan yang terlibat.
Surous
@ Οurous Bagaimana bahasa-bahasa itu biasanya menangani data array yang sewenang-wenang?
Adám
1
ada tiga kasus untuk penggunaan "normal" seperti yang saya lihat: hanya mengkhawatirkan satu level array (mis: reversebekerja pada array arbitrer tetapi hanya peduli pada level pertama), generik, atau kelas rekursif (kelas tipe / objek tergantung pada fungsional atau OOP, tetapi serupa kasus penggunaan). Dua yang terakhir biasanya jauh lebih bertele-tele.
Οurous
Bisakah kita menyimpan matriks sebagai array pointer ke pointer (dalam C atau asm), bukan array multi-dimensi yang tepat di mana semuanya berdekatan dalam memori? Saya cukup yakin semua bahasa tingkat tinggi / yang diketik secara normal dengan daftar yang bersarang secara acak sudah memperlakukan hal-hal sebagai daftar daftar, bukan matriks, jadi saya akan menganggapnya baik-baik saja.
Peter Cordes
@PeterCordes Tentu, silakan.
Adám

Jawaban:

8

APL (Dyalog) , 20 9 byte

⊃{⌽[⍺]⍵}/

Cobalah online!

Bagaimana?

/ - kurangi - ambil elemen paling kanan dalam input (array) dan terapkan fungsi dengan elemen kiri berikutnya sebagai argumen kiri

{⌽[⍺]⍵}- mundur dalam dimensi left argument( )

- Ratakan array yang tertutup

Uriel
sumber
8

JavaScript (Node.js) , 58 55 53 45 byte

Disimpan 8 byte berkat @Shaggy

Mengambil input sebagai (indications)(array), di mana indikasi adalah daftar Boolean.

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

Cobalah online!

Berkomentar

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
Arnauld
sumber
Hanya menggunakan rinplace of r||-1 tampaknya berhasil .
Shaggy
Akan f=([r,...b])=>a=>1/r?a.sort(_=>r).map(f(b)):abekerja Di ponsel saya jadi tidak bisa menguji dengan benar.
Shaggy
@ Shaggy, Bagus! Saya suka aliran pemrosesan yang agak tidak biasa ini.
Arnauld
6

Python 2 , 56 55 byte

f=lambda a,t:t and[f(l,t[1:])for l in a][::1|-t[0]]or a

Cobalah online!

TFeld
sumber
5

Jelly , 8 byte

”€ẋ”ṚpFv

Mengambil daftar dimensi 0-diindeks.

Cobalah online!

Bagaimana itu bekerja

”€ẋ”Ṛ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.
Dennis
sumber
1
Mengerikan. Sangat bagus!
Adám
5

R , 80 78 77 byte

Buat panggilan ke extractor R [dengan membuat daftar urutan terbalik di mana ditunjukkan. Mereka sebenarnya mengandung angka nol, yang diam-diam diabaikan. Hal drop=Fini diperlukan untuk mencegah menjatuhkan dimensi R secara default. Kita perlu revpanggilan ke indikator kebalikan dimensi, karena cara R mengisi array.

-2 terima kasih @Giuseppe

-1 menggunakan penugasan sebaris.

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

Cobalah online!

Sebutan terhormat kepada @JayCe yang datang dengan variasi yang mendapatkan hasil yang sama dengan panjang yang sama:

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

Cobalah online!

J.Apakah
sumber
1
78 byte jawaban yang sangat bagus!
Giuseppe
1
Jawaban yang sangat mendalam. Butuh beberapa saat untuk memahaminya sepenuhnya. Saya mencoba mereplikasi tanpa menggunakan do.call- lebih panjang pada 83 byte, masih memposting ini di sini sebagai komentar untuk referensi: TIO
JayCe
Sebenarnya, @JayCe, jawaban Anda yang hebat juga bisa di-golf hingga 78 byte!
J.
5

Haskell, 120 119 byte

fungsi f mengambil daftar dimensi-N dan daftar bool sebagai input

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)
Damien
sumber
1
Anda tidak perlu tanda kurung F r.
Ørjan Johansen
1
TIO link dengan test case dan golf 1-byte OJ.
Khuldraeseth na'Barya
4

05AB1E , 23 11 10 byte

'€s×'R«J.V

Cobalah online.

-12 byte terima kasih kepada @ Mr.Xcoder .

Input sebagai 0 nilai indeks kebenaran (yaitu [0,2,3]), yang merupakan input pertama.

Penjelasan:

'€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

Sebagai contoh: jika daftar input indeks adalah [0,2,3], itu akan membuat string berikut:

R€€R€€€R

Yang mana akan:

    €€€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

Jawaban 23 byte asli:

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

Input sebagai boolean-list (yaitu [1,0,1,1]), yang merupakan input pertama.

Cobalah online.

Penjelasan:

ć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

Sebagai contoh: Jika daftar input boolean adalah [1,0,1,1], itu akan membuat string berikut:

εεεR}R} }R

Yang mana akan:

  ε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
Kevin Cruijssen
sumber
1
Jawaban yang bagus, tapi ... uhm ... apakah byter 11 ini bekerja?
Tn. Xcoder
@ Mr.Xcoder Terima kasih! Itu memang jauh lebih mudah. Dan dapat golf 1 byte lebih dengan menambahkan masing-masing, alih-alih menambahkan dan kemudian membalikkan.
Kevin Cruijssen
@ Mr.Xcoder Btw, mengapa 'x*bekerja berulang xkali dan tanpa menggunakan swap, tetapi tidak berhasil '€*? EDIT: Hanya dalam warisan ..
Kevin Cruijssen
Versi lawasnya cukup buggy, mungkin karena fakta yang masih diurai sebagai operator meskipun itu dalam karakter literal? Tidak yakin jujur. Di versi yang baru, *tetap saja tidak berlaku sama.
Tn. Xcoder
3

JavaScript (Node.js) , 60 byte

Pendekatan (rekursif) yang berbeda. belum mengalahkan jawaban Arnauld ... belum ....

Mengambil input sebagai 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]))

Luis felipe De jesus Munoz
sumber
3

Pyth , 15 byte

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

Coba di sini!

Mengganggu, menangani case daftar dimensi kosong membutuhkan tidak kurang dari 2 byte ... Saya lebih suka menggunakan ssdi tempat jk.ntapi: | Mengasumsikan bahwa daftar yang akan diubah dapat diberikan dalam sintaks Pyth asli, sebagai string. Saya telah menulis konverter ke sintaks Pyth untuk membuat pengujian lebih mudah. Dalam kasus yang disayangkan bahwa OP memilih untuk tidak mengizinkan ini, 17-byter akan "memperbaikinya":

.v+jk.n*\_*L\ME\E
Tuan Xcoder
sumber
3

Japt , 15 14 byte

Dengan beberapa inspirasi dari solusi Arnauld .

Mengambil indikasi sebagai input pertama, sebagai array boolean dari 1s dan 0s.

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

Cobalah


Penjelasan

                   :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
Shaggy
sumber
3

Bersih , 122 112 byte

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

Cobalah online!

Versi jawaban Hasami Damien menggunakan sistem tipe pegolf Clean. Benar-benar menunjukkan kesamaan luas antara kedua bahasa.

Dijelaskan:

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
Suram
sumber
1

(Tidak teruji tapi saya pikir benar. keluaran as kompiler terlihat seperti apa yang saya harapkan. Akan diperbarui jika / ketika saya menemukan waktu untuk menulis test harness yang membuat dan mencetak struktur data ini.)

GNU C ++ (portable) 148 byte

#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 = pointer dan jatuh dari fungsi non-void UB) 120 byte

#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));}};

Ini adalah struct penghitung kedalaman, panjang, array {integer atau pointer}. Di tingkat bawah pohon non-biner ini ( depth==0), array intptr_tadalah array bilangan bulat. Di level yang lebih tinggi, ini struct m*disimpan diintptr_t . Traversal mengambil peran.

Fungsi R()sebaliknya adalah fungsi anggota karena itu menyimpan mendeklarasikan argumen, dan menyimpan banyak p->sintaks untuk mereferensikan anggota struct vs thispointer implisit .

Satu-satunya ekstensi GNU adalah anggota array fleksibel C99 untuk membuat struct berukuran variabel , yang didukung dalam C ++ sebagai ekstensi GNU. Saya bisa menggunakan *aanggota yang menunjuk ke array yang dialokasikan secara terpisah dan memiliki ini menjadi ISO C ++ biasa. (Dan itu sebenarnya akan menghemat byte tanpa memerlukan perubahan lain). Saya menulis ini sebagai implementasi mockup / referensi untuk versi asm.


Versi yang lebih pendek dengan hanya intmenyatakan R()sebagai kembali, intbukan void. Kedua bit hackery ini tidak berhubungan; ini hanya versi "berfungsi pada setidaknya satu implementasi".

Ini harus bekerja dengan baik pada target 32-bit (di mana intdapat menyimpan pointer), selama Anda mengkompilasi dengan gcc7 atau lebih tua, atau menonaktifkan optimasi. ( gcc8 -O3mengasumsikan bahwa eksekusi tidak dapat mencapai bagian bawah dari non- voidfungsi karena itu akan menjadi UB.) x86 gcc -m32 -O3harus berfungsi dengan baik dengan gcc7, seperti pada Godbolt mana saya memasukkan kedua versi (dalam ruang nama yang berbeda) dan versi non-anggota-fungsi .

Tidak disatukan

Function arg,, int r[]adalah larik bilangan bulat 0 / non-nol yang menunjukkan apakah kedalaman yang diberikan harus ditukar, dimulai dengan level paling luar.

#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

Ketika kita berulang, kita lewat r+1, jadi memeriksa kedalaman saat ini selalu *r.

Versi sebelumnya baru saja lewat rtidak berubah, dan diperiksa r[d]. Dengan anggota array yang fleksibel, saya perlu menyimpan beberapa jenis indikator tingkat terakhir karena a[]bukan pointer, ini adalah array yang benar tanpa tipuan. Tetapi dengan intptr_t *aanggota, saya tidak bisa hanya memiliki itu nullptruntuk tingkat daun, karena saya ingin itu menjadi nilai.

Membalikkan level saat ini sebelum atau setelah melintasi pohon seharusnya tidak menjadi masalah. Saya tidak mencoba melakukannya selama .

Saya tidak yakin itu std::reversesepadan dengan jumlah byte vs loop manual, terutama jika saya bisa bekerja pada memanggil R()setiap pointer tepat di suatu tempat di dalam loop itu. Tapi hanya jikad!=0

Peter Cordes
sumber
Wah, mengesankan.
Adám
@ Adám: terima kasih, golf turun secara alami dan baik setelah saya menulisnya. Saya ingin tahu apa yang dapat saya lakukan dalam kode mesin x86: P
Peter Cordes
1

Mathematica, 7 byte

Reverse

Fungsi. Berikan daftar bersarang sebagai argumen pertama, dan daftar level / dimensi 1 berbasis untuk membalikkan sebagai argumen kedua. Cobalah online!

Akhirnya, tantangan lain di mana Mathematica memiliki builtin!

LegionMammal978
sumber
lapisan untuk membalik ? TIO link mungkin?
Adám
@ Adam Yaitu, daftar dimensi untuk dibalik, umumnya disebut sebagai level dalam Mathematica.
LegionMammal978