Mảng thách thức # 2: Tách một mảng lồng nhau


36

Lưu ý: Đây là số 2 trong một loạt các thử thách . Đối với thử thách trước, bấm vào đây .

Danh sách lồng nhau

Để tách các giá trị trong danh sách lồng nhau, làm phẳng nó, sau đó bọc từng giá trị để nó ở cùng độ sâu lồng nhau như trước.

Đó là để nói, danh sách này:

[1, [2, 3], [4, 4, [5, 2], 1]]

Sẽ trở thành:

[1, [2], [3], [4], [4], [[5]], [[2]], [1]]

Các thách thức

Nhiệm vụ của bạn là viết một chương trình lấy bất kỳ danh sách số nguyên dương nào lồng nhau (trong giới hạn ngôn ngữ của bạn) và thực hiện thao tác tách này.

Bạn có thể gửi một hàm lấy danh sách làm đối số hoặc chương trình đầy đủ thực hiện I / O.

Vì đây là , bài nộp ngắn nhất (tính bằng byte) sẽ thắng! *

* Các lỗ hổng golf tiêu chuẩn bị cấm. Bạn biết khoan.


Các trường hợp thử nghiệm

Danh sách đầu vào sẽ chỉ bao gồm các số nguyên trong kích thước số nguyên tiêu chuẩn của ngôn ngữ của bạn. Để tránh các ràng buộc của ngôn ngữ ngăn chúng cạnh tranh, các giá trị sẽ không được lồng ở độ sâu hơn 10.

Bạn có thể cho rằng đầu vào sẽ không có danh sách phụ trống: ví dụ - [[5, []]]sẽ không được cung cấp. Tuy nhiên, danh sách chính có thể trống.

[]            ->  []

[[1, 2]]      ->  [[1], [2]]
[3, [4, 5]]   ->  [3, [4], [5]]
[3, [3, [3]]] ->  [3, [3], [[3]]]
[[6, [[7]]]]  ->  [[6], [[[7]]]]
[[5, 10], 11] ->  [[5], [10], 11]

Đừng ngần ngại để lại nhận xét nếu tôi bỏ lỡ một trường hợp góc.

Thí dụ

Tôi ném lại với nhau một cách nhanh chóng (ungolfed) giải pháp Python 3 là một ví dụ - bạn có thể kiểm tra nó trên repl.it .


Thêm một testcase có số lớn hơn một chữ số cho các câu trả lời dựa trên chuỗi.
orlp

@orlp ý hay.
FlipTack

2
Chúng ta có thể giả định một độ sâu tối đa nhất định? Nói, 16?
orlp

@orlp Tôi sẽ nói có, độ sâu lồng tối đa sẽ là 10, vì tôi quan tâm đến thuật toán và thực thi phương thức của bạn hơn các ràng buộc ngôn ngữ của bạn. Sẽ cập nhật chủ đề ngay bây giờ.
FlipTack

Tôi có thể xuất ra dưới dạng một chuỗi không?
Rohan Jhunjhunwala

Câu trả lời:


4

Brachylog , 16 byte

:{##:0&:ga|g}ac|

Hãy thử trực tuyến!

Giải trình

Example input: [1:[2:3]]

:{          }a     Apply the predicate below to each element of the list: [[1]:[[2]:[3]]]
              c    Concatenate: Output = [1:[2]:[3]]
               |   Or: Input = Output = []

  ##                 Input is a list: e.g. Input = [2:3]
    :0&              Call recursively the main predicate with this input: [2:3]
       :ga           Group each element in a list: Output = [[2]:[3]]
          |          Or (not a list): e.g. Input = 1
           g         Group into a list: Output = [1]

Không những gì Ztranh luận làm trên TIO? Không có nó, điều này dường như xuất ra với true / false, điều này làm cho nó có vẻ như Zlà cần thiết trong số byte.
FlipTack

@FlipTack Znói với Brachylog rằng đối số đầu ra là một biến. Đây là biến này được thống nhất với đầu ra kết quả. Khi bạn xóa nó, nó báo cho Brachylog, đầu ra là một biến ẩn danh và thay vào đó sẽ in xem vị từ chính thành công hay thất bại. Điều này giống như trong Prolog khi kết quả được "đặt" vào một biến.
Gây tử vong

Ok :) câu trả lời tốt đẹp!
FlipTack

19

Toán học, 24 21 byte

##&@@List/@#0/@#&/@#&

hoặc một trong số này:

##&@@List/@#&/@#0/@#&
##&@@List@*#0/@#&/@#&
##&@@List/@#&@*#0/@#&

Giải trình

Lý do này quá ngắn là về cơ bản nó là một đệ quy không yêu cầu trường hợp cơ sở rõ ràng.

Có rất nhiều đường cú pháp ở đây, vì vậy hãy bắt đầu bằng cách không hiểu điều này. &biểu thị một hàm không tên còn lại của nó, có đối số được viết là #. Bên trong hàm này #0đề cập đến chính hàm đó, cho phép người ta viết các hàm đệ quy không tên. Nhưng hãy bắt đầu bằng cách đặt tên cho hàm bên trong và kéo nó ra:

f[x_] := ##& @@ List /@ f /@ x
f /@ # &

Đường cú pháp quan trọng khác f/@xlà viết tắt của Map[f, x]tức là nó gọi fmọi yếu tố của x. Lý do f[x_] := ... f /@ xkhông dẫn đến đệ quy vô hạn là việc ánh xạ một thứ gì đó qua nguyên tử khiến nguyên tử không thay đổi mà không thực sự gọi hàm. Do đó, chúng ta không cần kiểm tra trường hợp cơ sở (phần tử hiện tại là số nguyên) một cách rõ ràng.

Vì vậy, chức năng fđầu tiên đệ quy xuống danh sách sâu nhất bên trong x, tại thời điểm đó f/@trở thành no-op. Sau đó, chúng tôi gọi sử dụng ##& @@ List /@trên đó. Ánh xạ Listqua danh sách chỉ đơn giản là bao bọc từng phần tử trong một danh sách riêng, do đó {1, 2, 3}trở thành {{1}, {2}, {3}}. Sau đó, chúng tôi áp dụng ##& cho nó, có nghĩa là đầu (tức là danh sách bên ngoài) được thay thế bởi ##&, vì vậy điều này biến thành ##&[{1}, {2}, {3}]. Nhưng ##&chỉ đơn giản trả về các đối số của nó dưới dạng Sequence(mà bạn có thể nghĩ là danh sách chưa được liệt kê hoặc một loại toán tử "splat" trong các ngôn ngữ khác).

Vì vậy, ##& @@ List /@biến một danh sách {1, 2, 3}thành {1}, {2}, {3}(loại, điều cuối cùng thực sự được gói trong đầu Sequence, nhưng điều đó sẽ biến mất ngay khi chúng ta sử dụng giá trị ở bất cứ đâu).

Điều đó đặt ra câu hỏi tại sao fbản thân nó không phải là giải pháp cho thách thức. Vấn đề là danh sách ngoài cùng nên được xử lý khác nhau. Nếu chúng ta có đầu vào, {{1, 2}, {3, 4}}chúng ta muốn {{1}, {2}, {3}, {4}}không {{1}}, {{2}}, {{3}}, {{4}} . Giải pháp ban đầu của tôi đã khắc phục điều này bằng cách chuyển kết quả cuối cùng dưới dạng danh sách các đối số Joinsẽ khôi phục cấp độ bên ngoài của danh sách, nhưng điều này chỉ bỏ qua cấp độ bên ngoài bằng cách sử dụng f chính nó trong bản đồ trên đầu ra. Do đó fchỉ được áp dụng cho các yếu tố riêng lẻ của danh sách ngoài cùng và không bao giờ được chạm vào danh sách đó.

Đối với ba giải pháp khác, giải pháp đầu tiên chỉ đơn giản là áp dụng đệ quy bên ngoài fmà giải pháp cũng hoạt động tốt. Hai giải pháp khác tránh Maphoạt động lặp lại bằng cách trước tiên soạn hai hàm và sau đó ánh xạ kết quả chỉ một lần.


8

J , 19 18 byte

(<@]/@,~>)S:0 1{::

Đây là một động từ ẩn danh nhận và trả về các mảng được đóng hộp, là phiên bản của J (khá cồng kềnh) của các mảng lồng nhau. Xem nó vượt qua tất cả các trường hợp thử nghiệm.

Giải trình

Điều này sử dụng các hoạt động hơi kỳ lạ {::( bản đồ ) và S:( lây lan ), hoạt động trên các mảng được đóng hộp. {::thay thế mỗi lá bằng đường dẫn đóng hộp đến lá đó. S:áp dụng một động từ nhất định cho độ sâu lồng cho trước, sau đó chia kết quả thành một mảng.

(<@]/@,~>)S:0 1{::  Input is y.
(        )          Let's look at this verb first.
        >           Open the right argument,
      ,~            append the left argument to it,
    /               then reduce by
 <@]                boxing. This puts the left argument into as many nested boxes
                    as the right argument is long.
                    This verb is applied to y
               {::  and its map
            0 1     at levels 0 and 1.
                    This means that each leaf of y is paired with its path,
                    whose length happens to be the nesting depth of y,
                    and the auxiliary verb is applied to them.
          S:        The results are spread into an array.

3

R, 199 byte

function(l){y=unlist(l);f=function(x,d=0){lapply(x,function(y){if(class(y)=='list'){f(y,d=d+1)}else{d}})};d=unlist(f(l));lapply(1:length(d),function(w){q=y[w];if(d[w]){for(i in 1:d[w])q=list(q)};q})}

Câu hỏi này đã CỨNG. Danh sách của R hơi kỳ lạ và hoàn toàn không đơn giản để lặp qua tất cả các yếu tố của danh sách phụ. Nó cũng không đơn giản để sau đó xác định độ sâu của danh sách đó. Sau đó, thách thức trở thành tái tạo danh sách với tất cả các yếu tố được tách ra, vì vậy chúng ta cũng cần một cách để thích nghi tạo ra một danh sách có độ sâu nhất định.

Giải pháp bao gồm hai phần lớn. Một hàm đệ quy lặp trên tất cả các danh sách và ghi lại độ sâu:

  f=function(x,d=0){
    lapply(x,function(y){
      if(class(y)=='list'){
        f(y,d=d+1)
      } else {
        d
      }})
  }

Khi chúng ta có độ sâu của mọi mục nhập của vectơ unlist(l), được lưu trữ trong d, chúng ta sẽ ngầm tạo một danh sách thông qua lapplyvà điền vào nó với chức năng sau:

  lapply(1:length(d),function(w){
    q=y[w]
    if(d[w]){
      for(i in 1:d[w]){
        q=list(q)
      }
    }
    q
  })

Trong lệnh gọi áp dụng này, chúng tôi tạo một đối tượng qcó giá trị của mục trong danh sách, kiểm tra độ sâu của nó và xem nó có khác không. Nếu nó bằng 0, chúng ta có thể để nó dưới dạng một giá trị số. Nếu nó khác không, chúng ta cần lồng nó vào số lượng danh sách đó. Vì vậy, chúng tôi gọi một dthời gian vòng lặp và gọi liên tục q=list(q).

lapplysau đó đặt tất cả các giá trị này qtrong một danh sách, tạo đầu ra mong muốn.

Hoàn thành chương trình với khoảng cách thích hợp và như vậy:

function(our.list){
  values <- unlist(our.list)
  f <- function(part.list, depth = 0){
    lapply(part.list, function(y){
      if(class(y)=='list'){
        f(y, depth <- depth + 1)
      } else {
        return(depth)
      }})
  }
  depths <- unlist(f(our.list))
  new.list <- lapply(1:length(depths), function(w){
    q <- values[w]
    if(depths[w] != 0){
      for(i in 1:depths[w]){
        q <- list(q)
      }
    }
    return(q)
  })
  return(new.list)
}

Thật tuyệt, đây là phương pháp tôi đã sử dụng với giải pháp Python ban đầu của mình cho các trường hợp thử nghiệm :)
FlipTack

is.list(y)thay vì class(y)=='list'? không thể xác minh rằng nó sẽ thực sự hoạt động.
Giuseppe



2

C (gcc), 147 byte

d=0,l,i;
P(n,c){for(;n--;)putchar(c);}
main(c){for(;~(c=getchar());l=i)i=isdigit(c),P((l<i)*d,91),P(i,c),P((l>i)*d,93),P(l>i,32),d+=(92-c)*(c>90);}

Ví dụ đầu vào:

1 [23 3] [40 4 [5 2] 1]

Ví dụ đầu ra:

1 [23] [3] [40] [4] [[5]] [[2]] [1]

2

xếp chồng , không biên dịch, 25 byte

{e d:e$wrap d 1-*}cellmap

Đây là một chức năng trong đó nó sửa đổi thành viên hàng đầu của ngăn xếp. Nếu bạn muốn một chức năng bonafide, chỉ cần thêm []vào đầu và cuối. Hãy thử nó ở đây!

Đây là phiên bản dễ đọc:

{ arr :
  arr { ele depth :
    ele   $wrap depth 1- * (* execute wrap n times, according to the depth *)
  } cellmap (* apply to each cell, then collect the results in an array *)
} @:a2
(1 (2 3) (4 4 (5 2) 1)) a2 out

Trường hợp thử nghiệm:

(1 (2 3) (4 4 (5 2) 1))    (* arg on TOS *)
{e d:e$wrap d 1-*}cellmap
out                        (* display TOS *)

Đầu ra không có dòng mới:

(1 (2) (3) (4) (4) ((5)) ((2)) (1))

*như lập luận để khối mã?
Hạ cấp

@Downgoat trong trường hợp này nó kết thúc d-1thời gian đối số . $funclà một chức năng có thể được thao tác.
Conor O'Brien

2

PHP, 101 94 byte

đã lưu 1 byte nhờ @Christoph, lưu thêm 6 byte lấy cảm hứng từ đó.

function s($a){foreach($a as$b)if($b[0])foreach(s($b)as$c)$r[]=[$c];else$r[]=$b;return$r?:[];}

chức năng đệ quy, khá thẳng về phía trước

phá vỡ

function s($a)
{
    foreach($a as$b)                // loop through array
        if($b[0])                       // if element is array
            foreach(s($b)as$c)$r[]=[$c];    // append separated elements to result
        else$r[]=$b;                    // else append element to result
    return$r?:[];                   // return result, empty array for empty input
}

Trường hợp nào kết quả được khởi tạo?
Neil

@Neil: PHP khôngnt yêu cầu khởi tạo rõ ràng. Hoặc là $rlấy các phần tử trong vòng lặp hoặc hàm trả về một mảng trống. Nó có thể mang lại thông báo, nhưng chúng không được in với cấu hình mặc định.
Tít

Điều đó không có nghĩa là bạn chỉ có thể gọi nó một lần sao?
Neil

1
Bạn cũng có thể bị điên : !cos(). cos()trả về nullcho mỗi mảng và một số float! = 0 cho mỗi số nguyên positiv. Ý tôi là ... ai quan tâm đến cảnh báo?
Christoph

1
@Christoph: cảnh báo được in, thông báo không (trong cấu hình mặc định của thje). Nhưng đó là ý tưởng tuyệt vời! Bật is_int: Đảo ngược điều kiện không Tiết kiệm bất cứ điều gì; Tôi cần một không gian giữa elseforeach. NHƯNG: $b[0]cho một số nguyên là NULL.
Tít

2

Python 2, 122 106 byte

Điểm số khá khủng khiếp, chỉ là một thực hiện đơn giản.

Cảm ơn @Zachary T đã giúp lưu 16 byte!

def x(l,a=[],d=0):
 n=lambda b:b and[n(b-1)]or l
 if'['in`l`:[x(e,a,d+1)for e in l];return a
 else:a+=n(d)

Gọi xvới một đối số để chạy. Vì một số lý do, nó chỉ có thể được chạy một lần.


Bạn có thể thay đổi a+=[n(l,d)]thành a+=n(l,d),(lưu ý dấu phẩy)
FlipTack

Bạn thậm chí có cần phải gán cho t?
Zacharý

Điều này có hoạt động khi bạn gọi nó nhiều hơn một lần?
Zacharý

Bạn có thể di chuyển nđến hàm và xóa đối số đầu tiên vì nó sẽ luôn như vậy l.
Zacharý


2

JavaScript (Firefox 30-57), 53 byte

f=a=>[for(e of a)for(d of e.map?f(e):[e])e.map?[d]:d]

Câu trả lời ES6 tốt nhất tôi có cho đến nay là 76 byte:

f=(a,r=[],d=0)=>a.map(e=>e.map?f(e,r,d+1):r.push((n=d=>d?[n(d-1)]:e)(d)))&&r

2
Trong cả hai khối mã, tôi nghĩ rằng bạn đã bỏ qua hàng đầu f=.
Conor O'Brien

@ ConorO'Brien Lại một lần nữa ...
Neil


1

Perl 6 , 60 47 byte

sub f{[$_~~List??|([$_] for .&f)!!$_ for |$^a]}

( Hãy thử trực tuyến. )

Giải trình:

  1. [... for |$^a]: Lặp lại mảng đầu vào và xây dựng một mảng mới từ nó.
  2. $_ ~~ List ?? ... !! ...: Đối với mỗi phần tử, kiểm tra xem nó có phải là một mảng không.
  3. |([$_] for .&f): Nếu phần tử là một mảng, áp dụng đệ quy hàm cho nó, lặp lại các phần tử của mảng mới được trả về từ lệnh gọi đệ quy đó, bọc từng phần tử trong một mảng của chính nó và đưa chúng vào danh sách bên ngoài.
  4. $_: Nếu phần tử không phải là một mảng, hãy chuyển nó vào trạng thái tương tự.

1

Haskell, 71 byte

data L=N Int|C[L] 
d#C l=((C .pure.d)#)=<<l
d#n=[d n]
f(C l)=C$(id#)=<<l

Một lần nữa tôi phải xác định loại danh sách của riêng mình, vì danh sách người bản địa của Haskell không thể được lồng tùy ý. Loại mới này Lcó thể được trả về từ một chức năng nhưng không được in theo mặc định, vì vậy để xem kết quả tôi xác định một showví dụ cho L:

instance Show L where
  show (N n)=show n
  show (C l)=show l

Bây giờ chúng tôi có thể thực hiện một số thử nghiệm trong REPL:

*Main> f $ C[N 1, C[N 2, N 3], C[N 4, N 4, C[N 5, N 2], N 1]]
[1,[2],[3],[4],[4],[[5]],[[2]],[1]]

*Main> f $ C[C[N 6, C[C[N 7]]]]
[[6],[[[7]]]]

Cách thức hoạt động: một đệ quy đơn giản vượt qua mức lồng nhau như là một hàm của các hàm Ctạo. Chúng tôi bắt đầu với chức năng nhận dạng idvà bất cứ khi nào có một danh sách (-> khớp mẫu d#C l=), chúng tôi sẽ thêm một lớp C(-> C .pure.d) nữa cho lệnh gọi đệ quy của #tất cả các thành phần của danh sách. Nếu chúng ta gặp một số, chúng ta chỉ cần áp dụng hàm cấp độ lồng dcho số đó.


0

APL (Dyalog) , 44 byte *

Chức năng tiền tố ẩn danh. Lấy danh sách APL lồng nhau làm đối số và trả về mảng APL lồng nhau.

∊{⊃⊂⍣⍵,⍺}¨{⊃¨(j∊⎕D)⊆+\-'[]'∘.=j←⎕JSON⍵}

Hãy thử trực tuyến!

{... } áp dụng các chức năng rõ ràng sau đây đối số được đại diện bởi :

⎕JSON⍵ chuyển đổi đối số thành JSON

j← lưu trữ trong j

'[]'∘.= bàn nơi j bằng dấu ngoặc mở (hàng trên cùng) và đóng (hàng dưới cùng)

-⌿ hàng trên trừ hàng dưới cùng (giảm chênh lệch dọc)

+\ tổng tích lũy (điều này mang lại mức lồng nhau cho mỗi ký tự)

(Giáo dục)⊆  phân vùng, bắt đầu một phân vùng mới bất cứ khi nào một 1 không trước bởi 1 trong ...

  j∊⎕D trong đó mỗi nhân vật jlà một thành viên của tập hợp D igits

⊃¨ chọn cái đầu tiên của mỗi cái (cái này cho mức lồng nhau trên mỗi số có nhiều chữ số)

∊{...  áp dụng các chức năng sau đây để mỗi cấp làm tổ ( ), sử dụng các yếu tố tương ứng từ ε nlisted (phẳng) lập luận như là đối số bên trái ( ):

,⍺ ravel (liệt kê) số (vì vô hướng không thể được bao quanh)

⊂⍣⍵ kèm theo thời gian

 tiết lộ (vì danh sách trong cùng là một bao vây)


* Sử dụng Dyalog Classic với ⎕ML←3(mặc định trên nhiều hệ thống), thay thế cho cho . Tio!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.