สุ่มกอล์ฟประจำวัน # 1: สุ่มสลับแถว


35

เกี่ยวกับซีรี่ส์

ฉันจะใช้ชุดเล็ก ๆ ของความท้าทายรหัสกอล์ฟหมุนรอบรูปแบบของการสุ่ม โดยทั่วไปจะเป็นสนามกอล์ฟ9-Hole แต่กระจายออกไปหลายคำถาม คุณสามารถเข้าร่วมการท้าทายใด ๆ เป็นรายบุคคลราวกับว่ามันเป็นคำถามปกติ

อย่างไรก็ตามฉันจะรักษากระดานผู้นำในทุกความท้าทาย ซีรีส์นี้จะมีการแข่งขันมากกว่า 9 รายการ (สำหรับตอนนี้) โดยจะมีการโพสต์หนึ่งรายการทุกสองวัน ผู้ใช้ทุกคนที่เข้าร่วมในการท้าทายทั้ง 9 รายการมีสิทธิ์ได้รับรางวัลทั้งชุด คะแนนโดยรวมของพวกเขาคือผลรวมของการส่งที่สั้นที่สุดของพวกเขาในแต่ละการท้าทาย (ดังนั้นหากคุณตอบคำถามที่ท้าทายสองครั้งจะมีเพียงการนับคำตอบที่ดีกว่าเท่านั้นต่อคะแนน) หากใครมีอันดับสูงสุดในกระดานผู้นำโดยรวมนี้เป็นเวลา28 วันฉันจะให้รางวัลแก่พวกเขาเป็นจำนวน500คน

แม้ว่าฉันจะมีไอเดียมากมายสำหรับซีรีส์ แต่ความท้าทายในอนาคตยังไม่เกิดขึ้น หากคุณมีข้อเสนอแนะใด ๆ โปรดแจ้งให้เราทราบเกี่ยวกับการโพสต์ Sandbox ที่เกี่ยวข้อง

หลุมที่ 1: สุ่มอาเรย์

งานแรกนั้นค่อนข้างง่าย: กำหนดอาเรย์ของจำนวนเต็มแบบไม่ว่างเปล่าสุ่มแบบสุ่ม มีกฎบางอย่างที่:

  • การสับเปลี่ยนที่เป็นไปได้ทุกครั้งจะต้องส่งคืนด้วยความน่าจะเป็นแบบเดียวกัน (ดังนั้นการสับเปลี่ยนควรมีการแจกแจงแบบเดียวกัน) คุณสามารถตรวจสอบว่าอัลกอริทึมของคุณเป็นชุด / เป็นกลางโดยการใช้ใน JavaScript บนมันจะสลับซึ่งจะผลิตเมทริกซ์ของอคติที่ - ผลควรมีลักษณะเป็นเครื่องแบบเป็นของตัว ins Fisher-Yatesหรือเรียงลำดับ (ลำดับแบบสุ่ม)
  • คุณต้องไม่ใช้วิธีการใด ๆ ในตัวหรือของบุคคลที่สามเพื่อสับเปลี่ยนอาร์เรย์หรือสร้างการเรียงสับเปลี่ยนแบบสุ่ม (หรือแจกแจงการเปลี่ยนลำดับทั้งหมด) โดยเฉพาะอย่างยิ่งในตัวฟังก์ชั่นแบบสุ่มคุณอาจจะใช้เพียง แต่จะได้รับจำนวนสุ่มเดียวในเวลา คุณอาจคิดว่าวิธีการสุ่มตัวเลขใด ๆ ในตัวทำงานใน O (1) และมีความสม่ำเสมออย่างสมบูรณ์แบบในช่วงเวลาที่ร้องขอ (ในแง่ทางคณิตศาสตร์ หากภาษาของคุณอนุญาตให้คุณรับรายการหมายเลขสุ่มm ได้ในครั้งเดียวคุณสามารถใช้สิ่งอำนวยความสะดวกนี้ได้หากตัวเลขmเป็นอิสระต่อกันและคุณนับเป็น O (m)
  • การใช้งานของคุณต้องไม่ซับซ้อนเกินเวลาที่ O (N)โดยที่Nคือขนาดของอาเรย์ที่จะถูกสับ ตัวอย่างเช่นคุณไม่สามารถ "เรียงตามตัวเลขสุ่ม"
  • คุณสามารถสับเปลี่ยนอาเรย์หรือสร้างอาเรย์ใหม่ (ซึ่งในกรณีนี้อาเรย์เก่าอาจถูกปรับเปลี่ยนตามที่คุณต้องการ)

คุณสามารถเขียนโปรแกรมหรือฟังก์ชั่นเต็มรูปแบบและรับอินพุตผ่าน STDIN อาร์กิวเมนต์บรรทัดคำสั่งอาร์กิวเมนต์ฟังก์ชันหรือพร้อมท์และสร้างเอาต์พุตผ่านค่าส่งคืนหรือโดยการพิมพ์ไปยัง STDOUT (หรือทางเลือกที่ใกล้เคียงที่สุด) หากคุณเขียนฟังก์ชันที่สับเปลี่ยนอาร์เรย์คุณไม่จำเป็นต้องส่งคืนแน่นอน (หากภาษาของคุณอนุญาตให้คุณเข้าถึงอาร์เรย์ที่ปรับเปลี่ยนหลังจากที่ฟังก์ชันส่งคืนแล้ว)

เข้าและส่งออกอาจจะอยู่ในรายชื่อที่สะดวกใด ๆ หรือรูปแบบสตริง แต่ต้องสนับสนุนจำนวนเต็มโดยพลการในช่วง-2 31 ≤ x <2วันที่ 31 โดยหลักการแล้วรหัสของคุณควรใช้กับอาร์เรย์ที่มีความยาวสูงสุด2 31แม้ว่าจะไม่จำเป็นต้องใส่ในหน่วยความจำของคุณหรือทำให้เสร็จภายในระยะเวลาที่เหมาะสม (ฉันแค่ไม่ต้องการเห็นการ จำกัด ขนาดโดยพลการของลูปฮาร์โค้ดหรือบางอย่าง)

นี่คือรหัสกอล์ฟดังนั้นการส่งที่สั้นที่สุด (เป็นไบต์) ชนะ

ลีดเดอร์บอร์ด

ตัวอย่างต่อไปนี้จะสร้างกระดานผู้นำสำหรับทุกความท้าทายของซีรี่ส์

เพื่อให้แน่ใจว่าคำตอบของคุณปรากฏขึ้นโปรดเริ่มต้นทุกคำตอบด้วยพาดหัวโดยใช้เทมเพลต Markdown ต่อไปนี้:

# Language Name, N bytes

ที่Nมีขนาดของส่งของคุณ หากคุณปรับปรุงคะแนนของคุณคุณสามารถเก็บคะแนนเก่าไว้ในพาดหัวโดยการตีพวกเขาผ่าน ตัวอย่างเช่น

# Ruby, <s>104</s> <s>101</s> 96 bytes

(ภาษาไม่ปรากฏขึ้นในปัจจุบัน แต่ตัวอย่างข้อมูลต้องการและแยกวิเคราะห์และฉันอาจเพิ่มกระดานผู้นำแบบแยกภาษาในอนาคต)


7
ฉันกำลังผิดหวังที่เราไม่ได้รับอนุญาตให้เป็น "ฉลาด" และใช้ฟังก์ชั่นอื่น ๆ ในห้องสมุดกว่า "ได้รับจำนวนสุ่ม" เราต้องการดูการสับเปลี่ยน Fisher-Yates อีก 69 รายการหรือไม่? โปรดพิจารณาลบกฎนี้ในงานในอนาคต นอกจากนี้ทำไมจึงมีข้อ จำกัด ด้านเวลาที่ซับซ้อน โปรดพิจารณาการผ่อนคลายอย่างน้อย O (n ^ 2); ฉันยังคิดว่าบางคนอาจพบว่ามีการนำกอล์ฟไปใช้โดยเฉพาะถ้าคุณอนุญาต O (n!)
anatolyg

7
@anatolyg การลบการ จำกัด จำนวนคำตอบเป็นอย่างใดอย่างหนึ่งsortby(random)(เหตุผลสำหรับการ จำกัด เวลา) หรือเพียง.shuffle()(เหตุผลสำหรับข้อ จำกัด ในตัว) ซึ่งฉันคิดว่าฉลาดน้อยกว่าการใช้ Fisher-Yates หรืออื่น ๆ เข้าใกล้
Martin Ender

1
หากมีการสับในตำแหน่งฟังก์ชั่นจะต้องคืนค่าอาเรย์หรือมีความเพียงพอที่จะแก้ไขหรือไม่? ฉันสามารถเขียนฟังก์ชั่นshuffle(array)แทนได้newArray=shuffle(array)หรือไม่?
Geobits

1
@Bakuriu การอ้างสิทธิ์ว่าคุณสามารถเรียงลำดับในเวลาเชิงเส้นได้หากหมายเลขที่กำหนดเป็นบิตเหมือนกับการอ้างสิทธิ์คุณสามารถทำอะไรก็ได้ใน O (1) หากขนาดอินพุตถูกแก้ไข ข้อ จำกัด ที่เกี่ยวข้องคืออาร์เรย์ขนาดคงที่ไม่ใช่จำนวนเต็มขนาดคงที่เนื่องจากขนาดอาร์เรย์เป็นตัวกำหนดว่าคุณต้องใช้ตัวเลขสุ่มขนาดไหน อย่างไรก็ตามข้อ จำกัด เกี่ยวกับความซับซ้อนของเวลานั้นแน่นอนว่าสำหรับอัลกอริธึมทั่วไปที่คุณใช้ในขณะที่ข้อ จำกัด เกี่ยวกับขนาดอินพุตอยู่ในตำแหน่งดังนั้นคุณไม่จำเป็นต้องใช้จำนวนเต็มความแม่นยำโดยพลการหากภาษาของคุณไม่ได้ใช้ .
Martin Ender

2
เหตุใดโซลูชันของAdámจึงมีขนาด 43319 ไบต์เมื่อเป็นจริง 14
boboquack

คำตอบ:


20

Dyalog APL, 25 24 ไบต์

ที่หนึ่งสำหรับโซลูชัน 25 ตัวอักษร: i{⊃a[⍺⍵]←a[⍵⍺]}¨?i←⌽⍳⍴a←⎕

                      a←⎕ ⍝ evaluated input, assign to "a"
                     ⍴a   ⍝ length
                    ⍳⍴a   ⍝ 1 2 .. length
                   ⌽⍳⍴a   ⍝ length .. 2 1
                 i←       ⍝ assign to "i"
                ?i        ⍝ random choices: (1..length)(1..length-1)..(1 2)(1)
i{            }¨?i        ⍝ for each index ⍺ and corresponding random choice ⍵
   a[⍺⍵]←a[⍵⍺]            ⍝ swap a[⍺] and a[⍵]
        ←                 ⍝ in Dyalog, assignment returns its right-hand side
  ⊃                       ⍝ first element, i.e. a[⍵]
                          ⍝ the result from {} is an array of all those a[⍵]

หลังจากการแปลงสมมูลบางอย่างข้างต้น:

i {}¨ ?i  ←→  i {}¨∘? i   ⍝ because A f∘g B ←→ A f g B
          ←→  {}¨∘?⍨ i    ⍝ because f⍨ B ←→ B f B

เราสามารถกำจัดการบ้านi←และบันทึกตัวละคร:

{⊃a[⍺⍵]←a[⍵⍺]}¨∘?⍨⌽⍳⍴a←⎕


3
... ใจ อ่อนไหว
danwyand

1
ภาษาที่ฉันต้องอ่านจากขวาไปซ้าย ว้าว!
Luminous

5
@ Lumin as มักจะเป็นกรณีที่มีสัญกรณ์ทางคณิตศาสตร์: sin cos ln sqrt x
ngn

4
@ngn เมื่อคุณพูดอย่างนั้นที่ทำให้ความคิดเห็นก่อนหน้าของฉันดูน่าหัวเราะ ฮ้า
ส่องสว่าง

5
@ronalchn มี 8 บิตการเข้ารหัสสำหรับ APL เช่นมีนี้หนึ่งหรือนี้คนอื่น ๆ ; ฉันได้ยินมาว่า Dyalog ใช้หนึ่งในนั้นแทน Unicode
anatolyg

12

รหัสเครื่อง 80386, 44 24 ไบต์

Hexdump ของรหัส:

60 8b fa 0f c7 f0 33 d2 f7 f1 49 8b 04 8f 87 04
97 89 04 8f 75 ed 61 c3

ขอบคุณ FUZxxl ใครแนะนำให้ใช้rdrandคำแนะนำ

นี่คือซอร์สโค้ด (สามารถคอมไพล์โดย Visual Studio):

__declspec(naked) void __fastcall shuffle(unsigned size, int array[])
{
    // fastcall convention:
    // ecx = size
    // edx = array
    _asm
    {
        pushad;             // save registers
        mov edi, edx;       // edi now points to the array

    myloop:
        rdrand eax;         // get a random number
        xor edx, edx;
        div ecx;            // edx = random index in the array

        dec ecx;            // count down
        mov eax, [edi + 4 * ecx];   // swap elements
        xchg eax, [edi + 4 * edx];  // swap elements
        mov [edi + 4 * ecx], eax;   // swap elements
        jnz myloop;

        popad;              // restore registers
        ret;
    }
}

อีกหนึ่งการดำเนินการของ Fisher-Yates การตีกอล์ฟส่วนใหญ่ทำได้โดยการส่งพารามิเตอร์ในการลงทะเบียน


1
คุณสามารถใช้rdrandสำหรับ shits และหัวเราะคิกคัก
FUZxxl

@FZZxxl ฉันลืมไปโดยสิ้นเชิง! เลวร้ายเกินไปก็เอาส่วนที่น่าสนใจมากที่สุดเกี่ยวกับคำตอบของฉัน ...
anatolyg

9

Java, 88 101

การสับเปลี่ยนพื้นฐาน Fisher-Yates เป็นการหลอกลวง ฉันรู้สึกว่ามันจะใช้งานได้ทั่วไปที่นี่เนื่องจากมันใช้งานง่ายและรวดเร็ว มีวง / งานที่ได้รับการยัดเยียดที่นี่ แต่จริงๆแล้วก็ไม่ได้มากนักสำหรับเล่นกอล์ฟ มันสั้นโดยธรรมชาติ

void t(int[]s){for(int i=s.length,t,x;i>0;t=s[x*=Math.random()],s[x]=s[i],s[i]=t)x=i--;}

ด้วยการขึ้นบรรทัดใหม่:

void t(int[]s){
    for(int i=s.length,t,x;
        i>0;
        t=s[x*=Math.random()],
        s[x]=s[i],
        s[i]=t
    )
        x=i--;
}

s[]ฟืนี้ในสถานที่การปรับเปลี่ยนอาร์เรย์เดิม โปรแกรมทดสอบ:

public class Shuffle {
    public static void main(String[] args) {
        int[] a = {1,2,3,4,5,6,7,8,9};
        new Shuffle().t(a);
        for(int b:a)
            System.out.print(b+" ");
    }
    void t(int[]s){for(int i=s.length,t,x;i>0;t=s[x*=Math.random()],s[x]=s[i],s[i]=t)x=i--;}
}

1
ไม่การท้าทายระบุว่าคุณสามารถสันนิษฐานได้ว่า " เป็นชุดที่สมบูรณ์แบบในช่วงที่ร้องขอ " ช่วงที่ร้องขอMath.random()มีขนาดซึ่งเป็นกำลังสองดังนั้นนี่จึงไม่เป็นไปตามข้อกำหนด
Peter Taylor

1
@PeterTaylor การตีความของ Jan และ Geobits เป็นวิธีที่ฉันตั้งใจทำตามกฎ - โดยที่คุณไม่ต้องกังวลกับความยาวรอบที่แท้จริงของ PRNG ของคุณ
Martin Ender

1
@ MartinBüttnerความยาวของรอบไม่ใช่ปัญหาที่นี่ - ซึ่งครอบคลุมโดยกฎของคุณ ความหยาบของลอยคือ
John Dvorak

3
@TheBestOne เป็นหนึ่งไบต์ที่สั้นกว่าโซลูชันไพ ธ อนที่โพสต์เพียงโพสต์ในปัจจุบันเท่านั้น)
Geobits

1
ไม่อีกแล้ว! : D
Sp3000

8

Python 2, 86 ไบต์

from random import*
def S(L):i=len(L);exec"i-=1;j=randint(0,i);L[i],L[j]=L[j],L[i];"*i

นี่คือฟังก์ชั่นที่สับเปลี่ยนอาร์เรย์โดยไม่ส่งคืนโดยใช้การสับเปลี่ยน Fisher-Yatesโดยตรง รับตัวเลขสุ่มจาก Python แพง ...

ขอบคุณ @xnor และ @colevk สำหรับเคล็ดลับ


การแสดงออกในช่วงนั้นดูค่อนข้างยุ่งยาก แน่นอนว่าสั้นลงที่จะนับด้วยตนเองว่าเป็นwhile i:i-=1;...?
xnor

@ xnor ใช่มันเป็น - ขอบคุณสำหรับสิ่งนั้น ฉันลืมไปตลอดว่าwhileมีแนวโน้มที่จะสั้นกว่าforสำหรับเรื่องแบบนี้ ...
Sp3000

1
Awww ... ตอนนี้คำตอบ Java ของฉันไม่ได้ตีนี้ ฉันมีความสุขมากในช่วงเวลาสั้น ๆ :(
Geobits

คุณสามารถบันทึกอีก 2 ไบต์ได้โดยการสร้างi=len(L)และวางการลดลงที่จุดเริ่มต้นของลูป while
colevk

8

J, 45 44 ตัวอักษร

นี่เป็นเรื่องยุ่งยาก

<@({.,?@#@}.({,<^:3@[{])}.)&>/@(<"0@i.@#,<)

นี่คือคำอธิบาย:

  1. # yการนับของy, ที่อยู่, yจำนวนขององค์ประกอบใน
  2. ?@# y: จำนวนสุ่มกระจายอย่างสม่ำเสมอในช่วงจากไป1(#y)-1
  3. x { y: รายการจาก ที่ดัชนีyx
  4. (<<<x) { y: รายการทั้งหมดยกเว้นรายการที่ดัชนีในxy
  5. x , y: y ต่อท้ายxไป
  6. x ({ , <^:3@[ { ]) y: รายการที่ดัชนีxในyจากนั้นรายการอื่น ๆ ทั้งหมด
  7. (?@# ({ , <^:3@[ { ]) ]) yสุ่มจากyนั้นรายการอื่น ๆ ทั้งหมด
  8. x {. y: ครั้งแรกที่xรายการนำมาyจาก
  9. x }. y: ครั้งแรกxรายการปรับตัวลดลงyจาก
  10. x ({. , }.) y: xรายการแรกที่นำมาจากyนั้นxรายการแรกที่ส่งมาจากy
  11. x ({. , (?@# ({ , <^:3@[ { ]) ])@}.) y: xรายการแรกที่นำมาจากyนั้นxรายการแรกจากการyประมวลผลเช่นเดียวกับในหมายเลข 7
  12. x ({. , ?@#@}. ({ , <^:3@[ { ]) }.) y: สิ่งเดียวกันที่มีการดึงลงเพื่อบันทึกอักขระหนึ่งตัว
  13. u/ y: u แทรกyระหว่างรายการของ
  14. < y: บรรจุกล่องy
  15. <"0 y: รายการของแต่ละชนิดบรรจุกล่องy
  16. i. y: จำนวนเต็มจากไป0y - 1
  17. i.@# y: จำนวนเต็มจากไป0(#y) - 1
  18. (<"0@i.@# , <) y: จำนวนเต็มจาก0ถึง(#y) - 1แต่ละกล่องแล้วyในกล่องเดียว นี่เป็นสิ่งจำเป็นเนื่องจากอาร์เรย์ใน J มีลักษณะเหมือนกัน กล่องจะซ่อนรูปร่างของเนื้อหา
  19. x u&v y: (v x) u (v y)เหมือน
  20. > y: y เปิดนั่นคือไม่มีกล่อง
  21. x ({. , ?@#@}. ({ , <^:3@[ { ]) }.)&> y วลีจากหมายเลข 12 ถูกนำไปใช้กับอาร์กิวเมนต์ที่ไม่มีกล่อง
  22. ({. , ?@#@}. ({ , <^:3@[ { ]) }.)&>/ yวลีจากหมายเลข 21 แทรกyระหว่างรายการ
  23. ({. , ?@#@}. ({ , <^:3@[ { ]) }.)&>/@(<"0@i.@# , <) yวลีจากหมายเลข 22 นำไปใช้กับผลของวลีจากหมายเลข 18 yหรือมีการเปลี่ยนแปลงเครื่องแบบของรายการของ

1
ฉันไม่สามารถแยกแยะความแตกต่างวงเล็บทั้งหมด และมวยสามตัว<@<@<@[ก็เป็นปริศนาเช่นกัน ... รอคำอธิบาย :)
randomra

2
เมื่อสิ่งนี้ได้รับการอธิบายฉันอาจจะมีโอกาสมากขึ้นที่จะตอบคำถามนี้ ;-)
John Dvorak

@randomra นี่คุณไป
FUZxxl

@JanDvorak คำอธิบายนั้นน่าพอใจหรือไม่?
FUZxxl

คำอธิบายที่ดี! ฉันไม่รู้เกี่ยวกับการใช้from( {) ทั้งหมดที่บรรจุอยู่ในกล่อง และฉันชอบ&>/เคล็ดลับในการจัดการรายการ ฉันแน่ใจว่าฉันสามารถใช้มันได้สองสามครั้งก่อน
Randomra

5

Pyth, 25 ไบต์

ทดสอบที่นี่

อีกหนึ่งการดำเนินการของ Fisher-Yates โดยพื้นฐานแล้วเป็นเช่นเดียวกับโซลูชั่น Python ของ @ Sp3000 ซึ่งมีหน่วยเป็น pyth

FNrlQ1KONJ@QN XXQN@QKKJ)Q

ขอบคุณ @Jakube สำหรับเคล็ดลับการแลกเปลี่ยน

<implicit>    Q=input()
FNrlQ1        For N in len(Q) to 1, only goes len Q-1 because how range implemented in pyth
 KON          K = random int 0-N
 J@QN         J=Q[N]
 <space>      Suppress print
 XXQN@QKKJ    Swap K and J
)             End for
Q             Print Q

คุณสามารถบันทึกสองไบต์ด้วยการรวมรายการที่ได้รับมอบหมายสองรายการ: `XXQN @ QKKJ` แทนที่จะเป็น 'XQN @ QK XQKJ`
Jakube

@ Jakube ขอบคุณสำหรับเคล็ดลับ ฉันรู้ว่าต้องมีวิธีในการแลกเปลี่ยนค่าในรายการและนี่เป็นสิ่งที่ฉลาดจริงๆ คุณควรเพิ่มเข้าไปในรายการเคล็ดลับ
Maltysen

4

Perl, 68 56 44

เช่นเดียวกับโซลูชันอื่น ๆ นี้ใช้อัลกอริทึมFisher-Yates

ใช้ความคิดเห็นของnutki , 12 ตัวอักษรจะถูกบันทึกโดยใช้$_แทน$iและดำเนินการในดัชนีอาร์เรย์

44:

sub f{@_[$_,$j]=@_[$j=rand$_,--$_]for 1..@_}

56:

sub f{$i=@_;$j=int(rand$i),@_[$i,$j]=@_[$j,$i]while$i--}

นี่คือ codegolf ตัวแรกของฉัน


ไม่ใช่การเริ่มต้นที่ไม่ดีฉันไม่ทราบว่าคุณสามารถใช้@_[...]เป็น rvalue เช่นนั้นได้ สามารถลงเล่นกอล์ฟต่อไปsub f{@_[$_,$j]=@_[$j=rand$_,--$_]for 1..@_}ได้
nutki

3

C, 63 61 60 ไบต์

i,t;s(a,m)int*a;{for(;m;a[m]=t)t=a[i=rand()%m--],a[i]=a[m];}

Fischer-Yates ที่นำอาร์เรย์ที่ได้รับมาจัดเรียงให้ตรง รวบรวมและเชื่อมโยงได้อย่างสมบูรณ์แบบด้วยคอมไพเลอร์ visual Studio (vs2013, ยังไม่ได้ทดสอบเวอร์ชันอื่น) และ Intel Compiler s(int array[], int length)ดีมองลายเซ็นของฟังก์ชั่น ฉันประทับใจอย่างแท้จริงฉันเอาชนะ Python และ Ruby

สิ่งนี้ถือว่าsrand()มีการเรียกและใช้แรนด์ () อย่างถูกต้อง แต่ฉันเชื่อว่ากฎนี้อนุญาตให้:

You may assume that any built-in random number method runs in O(1) and is perfectly uniform over the requested interval

เวอร์ชันที่มีรูปแบบสวยงาม:

index, temp;
shuffle(array, length) int* array;  {
    for(;length; array[index] = temp)
        index = rand() % length--,
        temp = array[length],
        array[length] = array[index];
}

ฉันคิดว่ามันเพียงพอที่จะทำให้ส่วนหัวของฟังก์ชั่นs(a,m)*a{แต่ฉันไม่แน่ใจและไม่ต้องการทดสอบอย่างใดอย่างหนึ่ง คุณอาจต้องการที่จะทำxor-swap a[i]^=a[m]^=a[i]^=a[m]เหมือนใน tนอกจากนี้ยังหลีกเลี่ยงความจำเป็นในการประกาศ
FUZxxl

@FUZxxl ผมเชื่อว่าการแลกเปลี่ยน xor i==mทำให้เกิดปัญหาหาก
Geobits

@Geobits แน่นอน ฉันพลาดความเป็นไปได้นั้น
FUZxxl

ฉันแค่พยายามคิดออกว่าทำไมมันถึงไม่ทำงาน ... น่าจะจำได้ นอกจากนี้ฉันต้องการs(a,m)int*aสตูดิโอภาพและคอมไพเลอร์ intel ไม่ได้ติดตั้ง gcc หรือเสียงดังกราวด์ทดสอบ แต่ฉันคิดว่าพวกเขาจะบ่น
นามแฝง

นี่เป็นสนามที่ค่อนข้างน่าประทับใจ หลังจากพยายามปรับเปลี่ยนมากมายที่ไม่ได้บันทึกอะไรเลยฉันก็จัดการเพื่อดูวิธีบันทึกอักขระ 2 ตัว หากคุณเปลี่ยนลำดับการแลกเปลี่ยนเพื่อให้คำสั่งการแลกเปลี่ยนแรกกลายเป็นt=a[i]คุณสามารถย้ายi=rand()%m--คำสั่งภายในเป็นดัชนีอาร์เรย์
Runer112

3

อ็อกเทฟ, 88 77 ไบต์

function s=r(s)for(i=length(s):-1:1)t=s(x=randi(i));s(x)=s(i);s(i)=t;end;end

การใช้งาน Fisher-Yates อื่น ... ควรตรงไปตรงมามากถ้าฉันเพิ่มการขึ้นบรรทัดใหม่และการเว้นวรรคบรรทัดปกติ:

function s=r(s)
  for(i=length(s):-1:1) # Counting down from i to 1
    t=s(x=randi(i));    # randi is builtin number generator for an int from 0 to i
    s(x)=s(i);
    s(i)=t;
  end
end

คำหลัก "สิ้นสุด" ฆ่าคะแนนกอล์ฟที่นี่อย่างน่าเสียดาย เฮ้ฉันสามารถใช้ "สิ้นสุด" แทน "endfor" และ "endfunction"!


1
เพียง FYI ที่ "ไบต์" ไม่จำเป็นต้องใช้จริงๆโดยรหัสที่มันก็ทำให้แน่ใจว่ามีเป็นพาดหัวที่มีเครื่องหมายจุลภาค (จะแยกภาษา) และจำนวนไม่น้อยกว่าหนึ่งหลังจากจุลภาคและแล้วก็เลือกสุดท้าย หมายเลขที่ไม่ถูกขีดฆ่า แม้ว่าจะมี "ไบต์" อยู่ในนั้นก็ยังดีอยู่ดี ;)
Martin Ender

1
คุณสามารถประหยัด 1 ไบต์โดยใช้แทนnumel lenghtเป็นโบนัสโปรแกรมของคุณจะทำงานร่วมกับอาเรย์แบบสองมิติหรือที่เรียกว่า matrices;)
paul.oderso

2

Java 8, 77

(x)->{for(int i=x.length,j,t;;t=x[j*=Math.random()],x[j]=x[i],x[i]=t)j=i--;};

มันเป็นการสละแลมบ์ดาint[]และการคืนโมฆะ ความพยายามครั้งแรกของฉันดูเหมือนจะไม่น่าสนใจมากฉันจึงตัดสินใจออกโดยโยนข้อยกเว้น

โปรแกรมทดสอบ:

interface shuff {
    void shuff(int[] x);
}
class Ideone
{
    public static void main (String[] args) throws java.lang.Exception
    {
        shuff s = (x)->{for(int i=x.length,j,t;;t=x[j*=Math.random()],x[j]=x[i],x[i]=t)j=i--;};
        int[] x = {3, 9, 2, 93, 32, 39, 4, 5, 5, 5, 6, 0};
        try {
            s.shuff(x);
        } catch(ArrayIndexOutOfBoundsException _) {}
        for(int a:x) System.out.println(a);
    }
}

1
มันเป็นการโกงที่จะใช้แลมบ์ดาเพื่อหลีกเลี่ยงการเขียนลายเซ็นของฟังก์ชั่นเมื่อคุณต้องให้ผู้ร่วมประชุมเพื่อใช้แลมบ์ดาที่ใดก็ได้? นอกจากนี้ ... คุณไม่สามารถวางวงเล็บไว้รอบ ๆMath.random()?
Rawling

1
@Rawling คุณสามารถลงคะแนนในคำถามเมตานี้ ปัจจุบันมีผู้ลงคะแนนเห็นด้วย lambdas 9 คะแนน, และ 0 คะแนน ใช่วงเล็บสามารถลบออกได้
feersum

หืมถ้ามีเมตาโพสต์และฉันทามติไกลแล้วก็ยิงออกไป (และสนุกไปกับคะแนนกอล์ฟสองระดับต่ำกว่าสำหรับฉัน: p)
Rawling

3
ฉันคิดว่ามันไม่ยุติธรรมสำหรับฟังก์ชั่นที่จะหยุดโดยยกเว้นในกรณีปกติใช่ไหม?
Qwertiy

1
@Qertert สำหรับตัวเขาแต่ละคน ... คุณคิดว่ามันไม่ยุติธรรมฉันคิดว่ามันเยี่ยมมาก
feersum


2

R, 79 ไบต์

f=function(x){n=length(x);for(i in 1:n){j=sample(i:n,1);x[c(i,j)]=x[c(j,i)]};x}

นี่เป็นการดำเนินการที่ตรงไปตรงมาของการสับเปลี่ยน Fisher-Yates ฟังก์ชัน R sampleดึงตัวอย่างสุ่มอย่างง่ายของขนาดที่กำหนดจากเวกเตอร์ที่กำหนดด้วยความน่าจะเป็นที่เท่ากัน นี่เรากำลังวาดภาพตัวอย่างที่สุ่มจากขนาด 1 ที่ซ้ำกันจากจำนวนเต็มi, ... n, ตามที่ระบุไว้ในคำถามนี้สามารถสันนิษฐานได้ว่าเป็น O (1) ดังนั้นในการดำเนินการทั้งหมดนี้ควรเป็น O (N)


2

Matlab, 67

ยังดำเนินการ Fisher-Yates

a=input('');n=numel(a);for i=1:n;k=randi(i);a([i,k])=a([k,i]);end;a

ฉันคิดว่ามันแย่เกินไปที่ฉันไม่สามารถใช้randpermฟังก์ชันของ Matlab ได้ แต่หลังจากที่เล่นซอไปรอบ ๆ ฉันคิดว่าฉันอาจจะดูที่มาของrandpermการดูว่ามันทำออกมาได้อย่างไรและฉันรู้สึกประหลาดใจเมื่อเห็นว่ามีเพียงหนึ่งบรรทัด: [~,p] = sort(rand(1,n))=)


2

Perl, 44

sub f{($_[$x],$_)=($_,$_[$x=rand++$i])for@_}

อีก Perl ใน 44 ตัวอักษร ตัวอย่างการใช้:

@x=(1..9);f(@x);print@x

2

Mathematica, 82 90 83 93 ไบต์

หมายเหตุ: รูปแบบนี้การสับเปลี่ยน Fisher-Yates เป็นวิธีการแก้ปัญหาจริงของ Martin Büttnerโดยมีการตัดโค้ดบางส่วนโดย alephalpha sเป็นอาร์เรย์อินพุต ไม่มีอะไรแฟนซี - สดใส แต่บางครั้งสิ่งที่ง่ายที่สุดที่เข้าใจยาก

f@s_:=(a=s;m=Length@a;Do[t=a[[r=RandomInteger@{1,m-1}]];a[[r]]=a[[m]]; a[[m]]=t,{n,1,m-1}];a)

คุณสามารถใช้Doที่นี่ Whileมันสั้นกว่า
alephalpha



2

K, 31 ตัวอักษร

f:{{l[i:x,1?x]:l@|i}'|!#l::x;l}

ไม่สั้นพอ ๆ กับที่ฉันใส่ก่อนหน้านี้ (ซึ่งถูกตัดสิทธิ์) ... โอ้ดี

มันเป็นพื้นฐานการสับเปลี่ยน Fisher-Yates นี้ถูกสร้างขึ้นมีจำนวนมากของความช่วยเหลือจากโคนารายชื่อผู้รับจดหมาย


2

JavaScript (ES6), 66

ฟังก์ชันนี้สลับอาร์เรย์ในตำแหน่ง นอกจากนี้ยังส่งกลับอาร์เรย์ผลพลอยได้ที่ไม่ได้เป็นเอาท์พุทสับและไม่ต้องพิจารณา

F=a=>a.map((v,i)=>a[a[i]=a[j=0|i+Math.random()*(a.length-i)],j]=v)

2

MATL , 16 ไบต์

XH`HnYr&)XHxvHHn

ลองออนไลน์!

Fisher-Yates ใน MATL เกือบหนึ่งในสามของโปรแกรมนี้อุทิศให้กับจดหมายHซึ่งสอดคล้องกับฟังก์ชั่นคลิปบอร์ดใน MATL

โดยทั่วไปจะจัดHเก็บรายการที่ไม่ได้ใช้งานจากอินพุตในขณะที่สแต็คคอยติดตามรายการที่สับ


2

Japt 12

rÈiMqZÄ Y}[]

ลองมัน!

-10 (ประมาณครึ่งหนึ่ง) ขอบคุณ @Shaggy!

ฉันอยากลองเล่นกอล์ฟภาษาและล่าม Japt มีเอกสารที่ดีและวิธีการทดลองใช้ในเบราว์เซอร์

ด้านล่างเป็นกลยุทธ์ที่ฉันทำ:

  • ลดการป้อนข้อมูลด้วยอาร์เรย์ว่าง
  • ในแต่ละขั้นตอนให้ค้นหาช่องสุ่มเพื่อแทรกองค์ประกอบปัจจุบัน

1
ยินดีต้อนรับสู่ Japtep ดีที่มีคุณกับเรา ฉันคิดว่าวิธีนี้ใช้งานได้ 9 ไบต์โดยใช้วิธีการเดียวกัน ถ้า RNG ไม่เป็นที่พอใจลองทำสิ่งนี้แทน
ขนปุย

@Shaggy - ขอบคุณสำหรับเคล็ดลับ! :) ฉันลงเอยด้วยการใช้โซลูชันที่ 2 ของคุณเล็กน้อย เนื่องจากพารามิเตอร์ตัวที่ 3 ของฟังก์ชั่นการลดคือดัชนีเราจึงทราบความยาว
dana

1

Javascript ES6, 69

a=>{m=a.length;while(m)[a[m],a[i]]=[a[i=~~(Math.random()*m--)],a[m]]}

มันคือ Fisher-Yates

PS: สามารถทดสอบได้ใน Firefox


@ MartinBüttnerลบออก :)
Qwertiy


1

Haskell, 170

import System.Random
import Data.Array.IO
s a=do(_,n)<-getBounds a;sequence$map(\i->do j<-randomRIO(i,n);p<-a%i;q<-a%j;writeArray a j p;return q)[1..n]where(%)=readArray

อีกวิธี Fisher-Yates แรงบันดาลใจจากอัลกอริทึมที่https://wiki.haskell.org/Random_shuffle

s เป็นฟังก์ชั่นที่มีลายเซ็นต์: IOArray Int a -> IO [a]


1

CJam - 30

q~_,,W%{_I=I)mr:J2$=@I@tJ@t}fI

ลองที่http://cjam.aditsu.net/

อินพุตตัวอย่าง: [10 20 30 40 50]
ตัวอย่างผลลัพธ์: 3020401050(เพิ่ม a pท้ายรหัสเพื่อพิมพ์สวย)

หากรหัสได้รับอนุญาตให้นำเข้าจากสแต็ค (เช่นฟังก์ชั่น) แล้วตัวละคร 2 ตัวแรกสามารถลบออกได้ลดขนาดถึง 28

คำอธิบาย:

รหัสยาวเกินกว่าที่ฉันคาดไว้เนื่องจากไม่มีตัวดำเนินการ "swap" สำหรับอาร์เรย์
(จะนำมาใช้ในภายหลัง: p)

q~            read and evaluate the input (let's call the array "A")
_,,           make an array [0 1 2 ... N-1] where N is the size of A
W%            reverse the array, obtaining [N-1 ... 2 1 0]
{…}fI         for I in this array
    _I=       push A[I]
    I)mr:J    push a random number from 0 to I (inclusive) and store it in J
              stack: A, A[I], J
    2$=       get A[J]
    @I@t      set A[I] = A[J]
              stack: former A[I], A
    J@t       set A[J] = former A[I]

ดังที่ได้กล่าวไว้ในความคิดเห็นฉันเกรงว่านี่ไม่ถูกต้อง อย่างน้อยที่สุด_ก็คือ O (N) (ภายในห่วง O (N)) น่าเสียดายที่ฉันไม่เห็นวิธีการแก้ไขใน CJam
Martin Ender

รายการได้รับการจัดการเหมือนวัตถุที่ไม่เปลี่ยนรูปดังนั้นการทำซ้ำจึงถูกนำไปใช้เป็นการทำสำเนาข้อมูลอ้างอิง จริงๆแล้วมันเป็นสิ่งtที่ฆ่ามันเนื่องจากมันไม่สามารถกลายพันธุ์รายการและตอนนี้ต้องสร้างสำเนา
Runer112

@ MartinBüttnerฉันกำลังจะโพสต์สิ่งเดียวกันกับ Runer112; ใช่อาจจะมีปัญหากับtฉันต้องการที่จะปรับปรุงมันในรุ่นอนาคต ..
aditsu

ดังนั้นรหัสนี้เป็นไปตามจิตวิญญาณของคำถาม แต่ไม่ใช่ "ตัวอักษร" เนื่องจากปัญหาการใช้ภาษาภายใน
aditsu

1

JavaScript (ES 6), 61

S=a=>(a.map((c,i)=>(a[i]=a[j=Math.random()*++i|0],a[j]=c)),a)

คุณสามารถทดสอบได้ที่นี่เพียงเพิ่มบรรทัดที่ระบุshuffle = S(Firefox เท่านั้น)


1

STATA, 161

di _r(s)
set ob wordcount($s)
token $s
g a=0
foreach x in $s{
gl j=floor(runiform()*_n)+1
replace a=`$j' if word($s,_n)=`x'
replace a=`x' if word($s,_n)=`$j'
}
l

ต้องการอินพุตเป็นตัวเลขคั่นด้วยช่องว่าง ฉันสามารถลบส่วนหัวและหมายเลขการสังเกตออกจากผลลัพธ์ได้หากคุณต้องการ แต่ไม่เช่นนั้นจะสั้นกว่า


มีอะไร_nในนี้?
Martin Ender

_n คือจำนวนการสังเกตปัจจุบัน
bmarks


1

SQF, 91 ไบต์

params["i"];{n=floor random count i;i set[_forEachIndex,i select n];i set[n,_x]}forEach i;i

1
นี้จะลำเอียง (ดู "การแลกเปลี่ยน (i <-> สุ่ม)" บนมันจะสุ่ม) แต่คุณสามารถทำให้มันกลายเป็นฟิชเชอร์เยตส์ (ซึ่งเป็นที่เป็นกลาง) โดยการแทนที่ด้วย%x %i
Martin Ender

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