ฟาโรสับเปลี่ยนอาเรย์


31

ฟาโรสับเปลี่ยนเป็นเทคนิคที่ใช้บ่อยโดยนักมายากลที่ "สับ" ดาดฟ้า เพื่อทำการสับไพ่แบบแฟโรคุณต้องตัดเด็คเป็น 2 ส่วนเท่ากันก่อน ตัวอย่างเช่น

[1 2 3 4 5 6 7 8]

แฟโรสับเป็น

[1 5 2 6 3 7 4 8]

สามารถทำซ้ำได้หลายครั้ง น่าสนใจพอถ้าคุณทำซ้ำครั้งนี้มากพอคุณจะกลับมาที่อาร์เรย์เดิมเสมอ ตัวอย่างเช่น:

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

ขอให้สังเกตว่า 1 อยู่ที่ด้านล่างและ 8 อยู่ที่ด้านบน ที่ทำให้นี้นอกสับเปลี่ยน นี่คือความแตกต่างที่สำคัญ

ความท้าทาย

รับอาร์เรย์ของจำนวนเต็มAและตัวเลขNส่งออกอาร์เรย์หลังจากN Faro shuffles Aอาจมีองค์ประกอบที่ทำซ้ำหรือลบ แต่จะมีองค์ประกอบจำนวนเท่า ๆ กันเสมอ คุณสามารถสมมติว่าอาร์เรย์จะไม่ว่างเปล่า คุณสามารถสันนิษฐานได้ว่าNจะเป็นจำนวนเต็มที่ไม่เป็นลบแม้ว่ามันอาจจะเป็น 0 คุณสามารถรับอินพุตเหล่านี้ในลักษณะที่สมเหตุสมผล คำตอบที่สั้นที่สุดในหน่วยไบต์ชนะ!

ทดสอบ 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]

และกรณีทดสอบขนาดใหญ่:

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]

ควรส่งออก:

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

อาร์เรย์สามารถมีองค์ประกอบเป็นศูนย์ได้หรือไม่
Leun Nun

@LeakyNun เราจะบอกว่าไม่คุณไม่ต้องจัดการกับองค์ประกอบใด ๆ
DJMcMayhem



1
การเปลี่ยนแปลงของเซต จำกัด หากทำซ้ำครั้งพอจะจบลงที่จุดเริ่มต้น นี่ไม่ใช่สิ่งพิเศษสำหรับ Shuffles ของแฟโร
Greg Martin

คำตอบ:



19

เป็นกลุ่ม62 59 54

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

ว้าว. นี่อาจเป็นสิ่งที่แฮ็คที่สุดที่ฉันเคยเขียนให้กับ PPCG และนั่นก็คือสิ่งที่พูด

อินพุตถูกนำมาเป็น N บนบรรทัดแรกตามด้วยองค์ประกอบของอาร์เรย์โดยแต่ละรายการจะอยู่ในบรรทัดของตัวเอง

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!

ที่จริงฉันอาจพบข้อบกพร่องหลายกลุ่มในขณะที่เขียนคำตอบนี้:

  • ไม่สามารถบันทึกมาโครการบันทึกภายในมาโครอื่น (เมื่อตั้งค่าข้อความด้วยตนเองไม่ใช่ด้วยq) หรือภายใน:*maps

  • :let @a='<C-v><cr>'<cr>i<C-r>a ส่งออกสองบรรทัดใหม่ไม่ใช่หนึ่งด้วยเหตุผลใดก็ตามที่เป็นความลับ

ฉันอาจตรวจสอบสิ่งเหล่านี้เพิ่มเติมในภายหลัง

ขอบคุณDr Green Eggs และ Ham DJสำหรับ 3 ไบต์!


4
นี่เป็นสิ่งที่สวยงามและน่ากลัว ฉันอาจมีความอดทนไม่พอที่จะทำเช่นนี้ในกลุ่ม :Pนอกจากนี้คุณสามารถถอด 2 ไบต์โดยทำ"rckแทนvgg"rcและคุณสามารถถอดอีก 5 โดยทำdw@"i@r<esc>แทนAA@R<C-v><esc><esc>0D@"
DJMcMayhem

@DrGreenEggsandHamDJ ไม่สามารถทำสิ่งแรกได้เพราะมันคว้า newline ต่อท้ายเช่นกัน แต่การเพิ่มประสิทธิภาพที่สองนั้นใช้งานได้ ขอบคุณ!
Doorknob

7

Python 2, 59 ไบต์

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

วิธีการที่แตกต่างซึ่งยาวกว่าคำตอบของ Python อื่นเล็กน้อย ใช้งานได้กับจำนวนองค์ประกอบที่เป็นบวกเท่านั้น

เช่น1, [1,2,3,4,5,6,7,8]ใช้อาร์เรย์และผนวกlen(L)/2-1สำเนาของตัวเองลบองค์ประกอบแรกเช่น

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

จากนั้นนำทุกlen(L)/2องค์ประกอบที่

[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 ไบต์

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

ขอบคุณ @ Sp3000 สำหรับการเล่นกอล์ฟที่ 11 ไบต์!

ทดสอบบนIdeone


6

Haskell, 62 ไบต์

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

ให้s = 2 · tเป็นขนาดของรายการ ฉันองค์ประกอบ -th ของรายการใหม่จะได้รับโดยการใช้ป้อนคำอธิบายรูปภาพที่นี่องค์ประกอบ -th ของรายการเก่าศูนย์การจัดทำดัชนีโมดูโลs

พิสูจน์: ถ้าi = 2 · kเป็นเลขคู่

                                         ป้อนคำอธิบายรูปภาพที่นี่

และถ้าi = 2 · k + 1 เป็นเลขคี่

                        ป้อนคำอธิบายรูปภาพที่นี่

ดังนั้นค่าที่ใช้สำหรับการทำดัชนีคือ 0, t , 1, t + 1, 2, t + 2, ...


5

J - 12 ไบต์

Adverb (!) ใช้จำนวน shuffles ทางด้านซ้ายและ array เพื่อสับเปลี่ยนทางด้านขวา

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

ตัวแยกวิเคราะห์ J มีกฎสำหรับการเขียนคำวิเศษณ์โดยปริยายแต่มีลำดับความสำคัญต่ำมาก: หากคุณต้องการใช้ขบวนคำกริยาเป็นอาร์กิวเมนต์ซ้ายคุณสามารถละเว้นวงเล็บที่จำเป็น ดังนั้นข้างต้นสั้นจริง ๆ(/:#/:@$0,#)^:ซึ่งใช้จำนวนของ shuffles ด้านซ้ายเป็นคำวิเศษณ์และจากนั้นกลายเป็นฟังก์ชัน monadic ใช้อาร์เรย์เพื่อสลับทางด้านขวา

ที่กล่าวว่าเราสับเปลี่ยนดังนี้ #คือความยาวของอาร์เรย์ดังนั้นจึง0,#เป็นรายการองค์ประกอบสองรายการ: 0 ตามด้วยสิ่งที่ไม่ใช่ศูนย์ จากนั้น#/:@$การลอกเลียนแบบที่เป็นรายการตราบเท่าที่อาร์เรย์การป้อนข้อมูลและใช้เวลาของการจัดเรียงเวกเตอร์

เวกเตอร์เรียงลำดับของรายการคือข้อมูลสำหรับวิธีการเรียงลำดับรายการ: Invdex (อิงตาม 0) ขององค์ประกอบที่เล็กที่สุดตามด้วยดัชนีของถัดไปเล็กที่สุดและอื่น ๆ ยกตัวอย่างเช่นการจัดเรียงของเวกเตอร์จึงจะเป็น0 1 0 1 ...0 2 4 ... 1 3 5 ...

ถ้าตอนนี้เจจัดเรียงเวกเตอร์แบบนี้แล้วมันจะสลับสับเปลี่ยน แต่นั่นจะไม่สำคัญเพราะเราจะ0 1 2 3 ...กลับมา ดังนั้นเราจึงใช้dyadic/:เพื่อจัดเรียงแถวลำดับการป้อนข้อมูลราวกับว่ามันเป็น 0 2 4 ... 1 3 5 ...แฟโรที่สับมัน

ตัวอย่างการใช้งานด้านล่าง ลองด้วยตัวคุณเองที่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 ไบต์

บันทึกแล้ว 1 ไบต์ขอบคุณ @issacg

usCc2GE

ลองมันออนไลน์ได้ที่นี่


2
อืม ... ต้องมีบางอย่างผิดปกติในคำตอบของ Jelly หาก Pyth beats Jelly
Leun Nun

2
สลับลำดับอินพุตและลบQเพื่อบันทึกไบต์ ต้องมีบางอย่างผิดปกติกับคำตอบของ Pyth ถ้า Jelly beats Pyth :)
isaacg

@isaacg darn, สาบานได้เลยว่าฉันเคยลองมาก่อน ทำไมจึงใช้งานได้ ไม่ควรขอที่เริ่มต้นuด้วยไม่มีและทำจุดคงที่?
Maltysen

@ Maltysen คุณพูดถูกฉันคิดว่ามันเกิดขึ้นกับการทดสอบเคสเดียวที่ฉันลอง ขอโทษสำหรับเรื่องนั้น.
isaacg

@LeakyNun ขอบคุณ@Dennisและ@issacg , Pythและ Jelly ตอนนี้เท่ากัน (7 ไบต์) ; D
Kevin Cruijssen


2

JavaScript (ES6), 61 51 ไบต์

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

ปรับเปลี่ยนอาร์เรย์อินพุตให้เข้าที่และส่งคืนสำเนาของอาร์เรย์ดั้งเดิม หากไม่สามารถยอมรับได้คุณ&&aสามารถต่อท้ายเพื่อกลับอาร์เรย์ที่ปรับเปลี่ยนได้ ใช้งานได้กับค่าเล็กน้อยnเนื่องจากข้อ จำกัด ของเลขคณิตจำนวนเต็มของ JavaScript 61เวอร์ชัน 60 ไบต์แบบเรียกซ้ำที่ทำงานกับขนาดใหญ่nขึ้นโดยอิงจากสูตรของ @ Lynn:

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

2

MATL 11 ไบต์

w:"tn2/e!1e

ขอบคุณ @Dennis สำหรับการแก้ไข

ลองออนไลน์!

คำอธิบาย

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)

ทำไมถึงwจำเป็น?
David

@ David นั่นคือการแก้ไข หากไม่มีมันสำหรับ N = 0 จะไม่ป้อนการวนซ้ำและอินพุตที่สองจะไม่ถูกนำมาใช้
Luis Mendo

อ่าน่ารำคาญ!
David

2

J, 22 19 17 ไบต์

3 ไบต์ขอบคุณที่ @Gareth

2 ไบต์ขอบคุณที่@algorithmshark

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

การใช้

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

>>STDIN อยู่ที่ไหนและ<<STDOUT อยู่ที่ไหน

เวอร์ชัน 22 ไบต์ก่อนหน้า:

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

การใช้

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

>>STDIN อยู่ที่ไหนและ<<STDOUT อยู่ที่ไหน


เนื่องจากกฎการแยกวิเคราะห์ของ Jคุณสามารถวาง parens ด้านนอกสำหรับ 2 chars
algorithmshark

ทางเลือกโดยใช้ดัชนีขนย้าย{~2,@|:@i.@,-:@#^:สำหรับ18 ไบต์
ไมล์

ทางเลือกอื่นที่ใช้17 ไบต์เช่นกัน[:,@|:]]\~_2%~#^:
ไมล์

@milesI เชื่อว่า,@|:@$~2,-:@#^:ทำงานได้ 15 ไบต์
Jonah

1

Mathematica 44 ไบต์

ด้วย 4 ไบต์ที่บันทึกไว้ต้องขอบคุณ @miles

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

Riffle @@ TakeDrop[#, Length@#/2] &~Nest~## &[list, nShuffles]แยกรายการออกเป็นสองรายการย่อยที่เท่ากันและสลับรายการRiffleเหล่านั้น


 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 }


ใช้TakeDropเราสามารถหาวิธีการแก้ปัญหาโดยใช้40 ไบต์เป็นRiffle@@TakeDrop[#,Length@#/2]&~Nest~##&ในขณะที่ยังมีการลำดับที่จะแยกวิเคราะห์เป็นข้อโต้แย้งเพิ่มเติมเพื่อ## Nest
ไมล์

@miles TakeDropการใช้งานที่ดีมากของ และมันจะดีกว่าที่จะใช้##เพื่อแทรกลำดับ
DavidC

1

APL, 23 21 ตัวอักษร

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

ไม่มีสมมติฐาน (ขอบคุณเดนนิส) และสั้นกว่า 1 ถ่าน:

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

ลองบนออนไลน์


1

java, 109 ไบต์

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

คำอธิบาย: มีรูปแบบการเคลื่อนย้ายองค์ประกอบเมื่อพวกเขาสับไพ่:

ให้ x เป็นดัชนีดั้งเดิม

ให้ y เป็นดัชนีใหม่

ให้ L เป็นความยาวของอาร์เรย์

  • y คือ double x
  • ถ้า x มากกว่าหรือเท่ากับครึ่งหนึ่งของ L ให้เพิ่ม y
  • เก็บ y ไว้ในขอบเขตของอาร์เรย์

หรือเป็นรหัส: y=(2*x+x/(L/2))%L

นี่ถือว่าสันนิษฐานว่าเริ่มต้นที่ 0 นี่คือรหัสที่อธิบายเพิ่มเติม:

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

ดู ideone สำหรับกรณีทดสอบ


ฉันรู้ว่ามันใช้เวลานานกว่าหนึ่งปี แต่คุณสามารถตีกอล์ฟได้สองสามส่วน: 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 ไบต์ - คำตอบปัจจุบันของคุณคือ 119 btw ไม่ใช่ 109 ดังนั้น -12 ไบต์) เนื่องจากคุณแก้ไขอาร์เรย์อินพุตไม่จำเป็นต้องส่งคืนดังนั้นคุณสามารถเปลี่ยนเป็นโมฆะเพื่อลดไบต์ โอ้และถ้าคุณแปลงเป็นแลมบ์ดาของ Java 8 คุณสามารถทำให้สั้นลงได้: 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 bytes )
Kevin Cruijssen

1

จูเลีย45 45ไบต์

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

ลองออนไลน์!

มันทำงานอย่างไร

เรา (อีกครั้ง) กำหนดผู้ประกอบการไบนารี\สำหรับงานนี้ ให้aเป็นอาร์เรย์และnเป็นจำนวนเต็มแบบไม่ลบ

ถ้าnเป็นค่าบวกเราจะสุ่มอาร์เรย์ สิ่งนี้สามารถทำได้โดยการปรับเปลี่ยนเป็นเมทริกซ์ที่มีความยาว (a) rows 2แถวและสองคอลัมน์ 'transposes [:]เมทริกซ์ส่งผลให้การสร้างสองแถวแล้วแฟบผลด้วย ตั้งแต่จูเลียเก็บเมทริกซ์ตามลำดับคอลัมน์หลักสิ่งนี้จะแทรกสองแถว

หลังจากนั้นเราเรียก\ซ้ำโดยใช้ shuffled aและn - 1 ( ~-n) เป็นอาร์กิวเมนต์เพื่อดำเนินการสับเพิ่มเติม เมื่อnถึง0เรากลับค่าปัจจุบันของ



0

ที่จริงแล้ว 15 ไบต์

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

ลองออนไลน์!

คำอธิบาย:

`;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



โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.