Faro xáo trộn một mảng


31

Một Faro ngẫu nhiên là một kỹ thuật thường xuyên được sử dụng bởi các nhà ảo thuật để "shuffle" một boong. Để thực hiện xáo trộn Faro, trước tiên bạn cắt boong thành 2 nửa bằng nhau sau đó bạn xen kẽ hai nửa. Ví dụ

[1 2 3 4 5 6 7 8]

Faro xáo trộn là

[1 5 2 6 3 7 4 8]

Điều này có thể được lặp đi lặp lại bất kỳ số lần. Thật thú vị, nếu bạn lặp lại đủ số lần này, bạn sẽ luôn trở lại mảng ban đầu. Ví dụ:

[1 2 3 4 5 6 7 8]
[1 5 2 6 3 7 4 8]
[1 3 5 7 2 4 6 8]
[1 2 3 4 5 6 7 8]

Lưu ý rằng 1 ở phía dưới và 8 ở trên cùng. Điều đó làm cho điều này một shuffle bên ngoài . Đây là một dấu hiệu đặc biệt quan trọng.

Các thách thức

Cho một mảng các số nguyên A và một số N , xuất ra mảng sau khi N Faro xáo trộn. A có thể chứa các phần tử lặp lại hoặc phủ định, nhưng nó sẽ luôn có số phần tử chẵn. Bạn có thể giả sử mảng sẽ không trống. Bạn cũng có thể giả sử rằng N sẽ là một số nguyên không âm, mặc dù nó có thể là 0. Bạn có thể lấy các đầu vào này theo bất kỳ cách hợp lý nào. Câu trả lời ngắn nhất bằng byte thắng!

Kiểm tra IO:

#N, A,                                              Output
1,  [1, 2, 3, 4, 5, 6, 7, 8]                        [1, 5, 2, 6, 3, 7, 4, 8]
2,  [1, 2, 3, 4, 5, 6, 7, 8]                        [1, 3, 5, 7, 2, 4, 6, 8]
7,  [-23, -37, 52, 0, -6, -7, -8, 89]               [-23, -6, -37, -7, 52, -8, 0, 89]
0,  [4, 8, 15, 16, 23, 42]                          [4, 8, 15, 16, 23, 42]
11, [10, 11, 8, 15, 13, 13, 19, 3, 7, 3, 15, 19]    [10, 19, 11, 3, 8, 7, 15, 3, 13, 15, 13, 19]

Và, một trường hợp thử nghiệm lớn:

23, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100]

Nên đầu ra:

[1, 30, 59, 88, 18, 47, 76, 6, 35, 64, 93, 23, 52, 81, 11, 40, 69, 98, 28, 57, 86, 16, 45, 74, 4, 33, 62, 91, 21, 50, 79, 9, 38, 67, 96, 26, 55, 84, 14, 43, 72, 2, 31, 60, 89, 19, 48, 77, 7, 36, 65, 94, 24, 53, 82, 12, 41, 70, 99, 29, 58, 87, 17, 46, 75, 5, 34, 63, 92, 22, 51, 80, 10, 39, 68, 97, 27, 56, 85, 15, 44, 73, 3, 32, 61, 90, 20, 49, 78, 8, 37, 66, 95, 25, 54, 83, 13, 42, 71, 100]  

Mảng có thể chứa các phần tử không?
Rò rỉ Nun

@LeakyNun Chúng tôi sẽ nói không, bạn không phải xử lý các yếu tố bằng không.
DJMcMayhem



1
Bất kỳ hoán vị của một tập hữu hạn, nếu lặp đi lặp lại đủ số lần, sẽ kết thúc trở lại nơi nó bắt đầu; Điều này không đặc biệt đối với xáo trộn Faro.
Greg Martin

Câu trả lời:



19

vim, 62 59 54

qrma50%mb:norm@q<cr>ggqOjdd'apjma'b@q<esc>0"qDJ<C-a>D@"i@r<esc>xxdd@"

Ồ Đây có thể là điều khó chịu nhất mà tôi đã viết cho PPCG, và đó là điều gì đó.

Đầu vào được lấy là N trên dòng đầu tiên theo sau là các phần tử của mảng, mỗi phần trên dòng riêng.

qr         first, we're going to record the contents of the @r macro. this is
             the macro which does the faro-shuffle operation.
  ma       set the mark 'a at the beginning of the file
  50%      move to the 50% point of the file (i.e. halfway down)
  mb       set another mark here
  :norm@q  evaluate the recursive macro @q. we'll get to what that does later,
             but the interesting part here is that it's :norm@q instead of @q.
             this is because a recursive macro terminates at the end of the
             file, which means when @q terminates, @r would also abort, which
             would make calling it with a count impossible. running @q under
             :norm prevents this.
  gg       move back to the top of the file for the next iteration
q          end recording
O          now we're inserting contents of the @q macro, the recursive part
             we can't record it directly because it's destructive
  j        move to line directly below mark 'b (which was just set before @q)
  dd       delete this line and bring it...
  'ap      up after mark 'a (which starts on line 1, bringing the N/2th line
             directly below line 1, aka line 2)
  jma      replace mark 'a one line below this so that the next time we call
             'ap, the line from the second half is interleaved with the lines
             from the first half
  'b       jump back to mark 'b (remember, 'b is the last line of the first
             half of the file, originally reached via 50%)
  @q       call ourselves, causing the macro to run until hitting EOF
0"qD       delete this into register "q
J          delete the empty line that remains
<C-a>      here's another interesting bit: we want to run @r N times. but 0@r
             means "go to column 0, and then run @r once." so we have to
             increment the input number...
D@"        and then *that* many times...
  i@r        insert @r...
xx         ... and finally, delete two characters, which is the extra @r from
             the increment
dd         delete the sequence of @rs into the "" register...
@"         and run it!

Tôi thực sự có thể tìm thấy một số lỗi vim trong khi viết câu trả lời này:

  • không thể ghi macro trong các macro khác (khi cài đặt văn bản theo cách thủ công, không phải với q) hoặc trong :*maps.

  • :let @a='<C-v><cr>'<cr>i<C-r>a xuất ra hai dòng mới, không phải một, vì bất kỳ lý do phức tạp nào.

Tôi có thể điều tra những cái đó sau.

Cảm ơn Dr Green Eggs và Ham DJ cho 3 byte!


4
Điều này thật đẹp và kinh khủng. Tôi có lẽ không đủ kiên nhẫn để làm điều này trong vim. :PNgoài ra, bạn có thể cất cánh 2 byte bằng cách làm "rckthay vgg"rc, và bạn có thể cất cánh 5 khác bằng cách làm dw@"i@r<esc>thay vìAA@R<C-v><esc><esc>0D@"
DJMcMayhem

@DrGreenEggsandoutDJ Không thể làm điều đó đầu tiên vì điều đó cũng có một dòng mới, nhưng tối ưu hóa thứ hai đó hoạt động. Cảm ơn!
Doorknob

7

Python 2, 59 byte

def f(n,L):exec"l=len(L)/2;L=(L+L[1:]*~-l)[::l];"*n;print L

Một cách tiếp cận khác, hơi dài hơn các câu trả lời Python khác. Chỉ hoạt động cho số lượng tích cực chẵn của các yếu tố.

ví dụ: 1, [1,2,3,4,5,6,7,8]lấy mảng và nối các len(L)/2-1bản sao của chính nó trừ phần tử đầu tiên, vd

[1,2,3,4,5,6,7,8,2,3,4,5,6,7,8,2,3,4,5,6,7,8,2,3,4,5,6,7,8]

Sau đó lấy mọi len(L)/2yếu tố thứ.

[1,2,3,4,5,6,7,8,2,3,4,5,6,7,8,2,3,4,5,6,7,8,2,3,4,5,6,7,8]
 ^       ^       ^       ^       ^       ^       ^       ^

6

Python, 68 57 byte

f=lambda n,x:n and f(n-1,sum(zip(x,x[len(x)/2:]),()))or x

Cảm ơn @ Sp3000 vì đã chơi golf 11 byte!

Kiểm tra nó trên Ideone .


6

Haskell, 62 byte

0!a=a
n!a|s<-length a=(n-1)![a!!mod(div(s*i+i)2)s|i<-[0..s-1]]

Đặt s = 2 · t là kích thước của danh sách. Phần tử thứ i của danh sách mới có được bằng cách lấy nhập mô tả hình ảnh ở đâyphần tử thứ của danh sách cũ, không có chỉ mục, modulo s .

Chứng minh: nếu i = 2 · k là chẵn thì

                                         nhập mô tả hình ảnh ở đây

và nếu i = 2 · k + 1 là số lẻ, thì

                        nhập mô tả hình ảnh ở đây

Do đó, các giá trị được sử dụng để lập chỉ mục là 0, t , 1, t + 1, 2, t + 2, Nhẫn


5

J - 12 byte

Trạng từ (!) Lấy số lần xáo trộn ở bên trái và mảng để xáo trộn ở bên phải.

/:#/:@$0,#^:

Trình phân tích cú pháp J có các quy tắc để viết các trạng từ ngầm , nhưng chúng có độ ưu tiên rất thấp: nếu bạn muốn sử dụng một chuỗi động từ làm đối số bên trái, bạn có thể bỏ qua một bộ dấu ngoặc đơn cần thiết khác. Vì vậy, ở trên thực sự là viết tắt của từ này (/:#/:@$0,#)^:, lấy số lần xáo trộn ở bên trái làm trạng từ, và sau đó trở thành một hàm đơn âm lấy mảng để xáo trộn ở bên phải.

Điều đó nói rằng, chúng tôi xáo trộn như sau. #là độ dài của mảng, do đó, 0,#một danh sách hai phần tử: 0 theo sau là một số khác. Sau đó #/:@$sao chép nó vào một danh sách miễn là mảng đầu vào và lấy vectơ sắp xếp của nó .

Vectơ sắp xếp của danh sách là thông tin về cách sắp xếp danh sách: invdex (dựa trên 0) của phần tử nhỏ nhất, theo sau là chỉ mục của phần tử nhỏ nhất tiếp theo, v.v. Ví dụ, vectơ sắp xếp của 0 1 0 1 ...ý chí là như vậy 0 2 4 ... 1 3 5 ....

Nếu bây giờ J sắp xếp vectơ sắp xếp này, nó sẽ Faro-shuffle nó; nhưng điều đó thật tầm thường, vì chúng tôi sẽ 0 1 2 3 ...quay trở lại. Vì vậy, chúng tôi sử dụng dyadic/: để sắp xếp mảng đầu vào như thể nó là 0 2 4 ... 1 3 5 ... Faro xáo trộn nó.

Ví dụ sử dụng dưới đây. Hãy thử nó tại tryj.tk !

   1 (/:#/:@$0,#^:) 1 2 3 4 5 6 7 8
1 5 2 6 3 7 4 8

   f =: /:#/:@$0,#^:

   2  f  1 2 3 4 5 6 7 8
1 3 5 7 2 4 6 8

   7  f  _23 _37 52 0 _6 _7 _8 89   NB. "negative 1" is spelled _1
_23 _6 _37 _7 52 _8 0 89

   1  f  0 0 0 0 1 1 1              NB. odd-length lists
0 1 0 1 0 1 0

5

Pyth - 8 7 byte

đã lưu 1 byte nhờ @issacg

usCc2GE

Hãy thử trực tuyến tại đây .


2
Hmm ... phải có điều gì đó sai trong câu trả lời của Jelly nếu Pyth đánh bại Jelly.
Nữ tu bị rò rỉ

2
Hoán đổi thứ tự đầu vào và loại bỏ Qđể lưu một byte. Phải có điều gì đó sai với câu trả lời của Pyth nếu Jelly đánh bại Pyth. :)
isaacg

@isaacg chết tiệt, có thể đã thề rằng tôi đã thử điều đó trước đây. Tại sao nó hoạt động? Không nên móc vào mặc định cho uKhông và làm điểm cố định?
Maltysen

@Maltysen Bạn nói đúng, tôi nghĩ nó chỉ xảy ra với một trường hợp thử nghiệm mà tôi đã thử. Xin lỗi vì điều đó.
isaacg

Cảm ơn @LeakyNun để @Dennis@issacg , Pyth và Jelly nay đều bình đẳng (7 byte). ; D
Kevin Cruijssen


2

JavaScript (ES6), 61 51 byte

(n,a)=>[...a].map((e,i)=>a[(i<<n)%~-a.length||i]=e)

Sửa đổi mảng đầu vào tại chỗ và trả về một bản sao của mảng ban đầu. Nếu điều này là không thể chấp nhận, &&acó thể được hậu tố để trả về mảng đã sửa đổi. Chỉ hoạt động cho các giá trị nhỏ ndo các giới hạn của số học số nguyên của JavaScript. 61 phiên bản đệ quy 60 byte hoạt động với công suất lớn hơn n, dựa trên công thức của @ Lynn:

f=(n,a,l=a.length)=>n?f(n-1,a.map((_,i)=>a[(i*-~l>>1)%l])):a

2

MATL , 11 byte

w:"tn2/e!1e

Cảm ơn @Dennis đã chỉnh sửa

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

Giải trình

w         % Take the two inputs N and A. Swap them
:         % Generate [1 2 ... N]
"         % Repeat N times
  tn2/    %   Duplicate A. Number of elements divided by 2
  e       %   Reshape to that number of rows
  !       %   Transpose
  1e      %   Reshape to one row
          % End (implicit)
          % Display (implicit)

Tại sao wcần thiết?
David

@David Đó là sự điều chỉnh. Không có nó, với N = 0, vòng lặp không được nhập và đầu vào thứ hai không được thực hiện
Luis Mendo

Ahh thật phiền phức!
David

2

J, 22 19 17 byte

3 byte nhờ @Gareth .

2 byte nhờ @alerskymshark .

-:@#({.,@,.}.)]^:

Sử dụng

>> f =: -:@#({.,@,.}.)]^:
>> 2 f 1 2 3 4 5 6 7 8
<< 1 3 5 7 2 4 6 8

Trong trường hợp >>là STDIN và <<là STDOUT.

Phiên bản 22 byte trước:

({~[:,/@|:@i.2,-:@#)^:

Sử dụng

>> f =: ({~[:,/@|:@i.2,-:@#)^:
>> 2 f 1 2 3 4 5 6 7 8
<< 1 3 5 7 2 4 6 8

Trong trường hợp >>là STDIN và <<là STDOUT.


Do quy tắc phân tích cú pháp của J , bạn có thể thả các dấu ngoặc ngoài cho 2 ký tự.
thuật toán

Thay thế bằng cách sử dụng một chỉ mục chuyển đổi {~2,@|:@i.@,-:@#^:cho 18 byte .
dặm

Một cách khác có sử dụng 17 byte cũng[:,@|:]]\~_2%~#^:
dặm

@milesI tin rằng ,@|:@$~2,-:@#^:hoạt động trong 15 byte
Jonah

1

Toán học 44 byte

Với 4 byte được lưu nhờ @miles.

Riffle@@TakeDrop[#,Length@#/2]&~Nest~##&

Riffle @@ TakeDrop[#, Length@#/2] &~Nest~## &[list, nShuffles]chia danh sách thành hai danh sách con bằng nhau và xáo trộn Rifflechúng.


 Riffle @@ TakeDrop[#, Length@#/2] &~Nest~## &[Range@8, 1]

{1, 5, 2, 6, 3, 7, 4, 8}


Riffle @@ TakeDrop[#, Length@#/2] &~Nest~## &[Range@100, 23]

{1, 30, 59, 88, 18, 47, 76, 6, 35, 64, 93, 23, 52, 81, 11, 40, 69, 98, 28, 57, 86, 16, 45, 74, 4 , 33, 62, 91, 21, 50, 79, 9, 38, 67, 96, 26, 55, 84, 14, 43, 72, 2, 31, 60, 89, 19, 48, 77, 7, 36 , 65, 94, 24, 53, 82, 12, 41, 70, 99, 29, 58, 87, 17, 46, 75, 5, 34, 63, 92, 22, 51, 80, 10, 39, 68 , 97, 27, 56, 85, 15, 44, 73, 3, 32, 61, 90, 20, 49, 78, 8, 37, 66, 95, 25, 54, 83, 13, 42, 71, 100 }


Sử dụng TakeDropchúng ta có thể tìm thấy một giải pháp sử dụng 40 byte như Riffle@@TakeDrop[#,Length@#/2]&~Nest~##&đồng thời cũng tham gia trình tự ##để được phân tích như các đối số bổ sung Nest.
dặm

@miles. Sử dụng rất tốt đẹp của TakeDrop. Và tốt hơn là sử dụng ##để chèn chuỗi.
DavidC

1

APL, 23 21 ký tự

({⊃,/⍵(↑,¨↓)⍨2÷⍨⍴⍵}⍣N)A

Không có giả định (Cảm ơn Dennis) và 1 char ngắn hơn:

({{∊,⌿2(2÷⍨≢⍵)⍴⍵}⍣⎕)⎕

Hãy thử nó trên mạng .


1

java, 109 byte

int[]f(int[]a,int n){for(int x,q=a.length,d[];0<n--;a=d){d=new int[q];for(x=0;x<q;x++)d[(2*x+2*x/q)%q]=a[x];}return a;}

Giải thích: Có một mô hình về cách các phần tử di chuyển khi chúng được xáo trộn:

Đặt x là chỉ số ban đầu

hãy để y là chỉ số mới

Đặt L là chiều dài của mảng

  • y là gấp đôi x
  • nếu x lớn hơn hoặc bằng một nửa L thì tăng y
  • giữ y trong giới hạn của mảng

hoặc dưới dạng mã: y=(2*x+x/(L/2))%L

Điều này giả định rằng các dấu hiệu bắt đầu từ 0. Đây là đoạn mã được giải thích thêm:

int[] faroShuffle( int[] array, int numberOfShuffles ) {
    //repeat the faro shuffle n times
    for( int index, length=array.length, destination[]; 0<numberOfShuffles--; array=destination ) {
        //new array to copy over the elements
        destination=new int[length];
        //copy the elements into the new array
        for( index=0; index<length; index++ )
            destination[(2*index+2*index/length)%length]=array[index];
        //at the end of each loop, copy the reference to the new array and use it going forward
    }
    return array;
}  

xem ideone cho các trường hợp thử nghiệm


Tôi biết đã hơn một năm, nhưng bạn có thể chơi gôn một vài phần: void f(int[]a,int n){for(int x,q=a.length,d[];0<n--;a=d)for(d=new int[q],x=0;x<q;)d[(2*x+2*x/q)%q]=a[x++];}( 107 byte - câu trả lời hiện tại của bạn là 119 btw, không phải 109, vì vậy -12 byte). Vì bạn sửa đổi mảng đầu vào, không cần trả về nó, vì vậy bạn có thể thay đổi nó thành một khoảng trống để giảm byte. Ồ, và nếu bạn chuyển đổi sang lambda Java 8 với việc currying, bạn có thể làm cho nó thậm chí còn ngắn hơn: a->n->{for(int x,q=a.length,d[];0<n--;a=d){d=new int[q];for(x=0;x<q;x++)d[(2*x+2*x/q)%q]=a[x];}}( 96 byte )
Kevin Cruijssen

1

Julia, 45 42 byte

a\n=n>0?reshape(a,endof(a)÷2,2)'[:]\~-n:a

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

Làm thế nào nó hoạt động

Chúng tôi (lại) định nghĩa toán tử nhị phân \cho tác vụ này. Đặt a là một mảng và n là một số nguyên không âm.

Nếu n dương, chúng ta xáo trộn mảng. Điều này đạt được bằng cách định hình lại nó thành một ma trận có độ dài (a) 2 hàng và hai cột. 'hoán đổi ma trận kết quả, tạo hai hàng, sau đó làm phẳng kết quả với [:]. Vì Julia lưu trữ ma trận theo thứ tự chính cột, điều này xen kẽ hai hàng.

Sau đó, chúng ta gọi \đệ quy với xáo trộn an - 1 ( ~-n) làm đối số, do đó thực hiện các xáo trộn bổ sung. Khi n đạt 0 , chúng ta trả về giá trị hiện tại của a .



0

Trên thực tế, 15 byte

`;l½≈@│t)HZ♂i`n

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

Giải trình:

`;l½≈@│t)HZ♂i`n
`            `n  do the following n times:
 ;l½≈              push half the length of the array
     @             swap
      │            duplicate entire stack
       t)H         last L//2 elements, first L//2 elements
          Z♂i      zip, flatten each element

0

Prolog, 116 byte

a([],[[],[]]).
a([H,I|T],[[H|U],[I|V]]):-a(T,[U,V]).
f(X,0,X).
f(X,N,Y):-N>0,M is N-1,f(X,M,Z),a(Z,[A,B]),append(A,B,Y).

Sử dụng

?- f([1,2,3,4,5,6,7,8],2,X).
X = [1, 5, 2, 6, 3, 7, 4, 8] ;
false.


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.