Випадковий гольф дня №1: Перемішайте масив


35

Про серію

Я буду проводити невелику серію проблем із кодовим гольфом, що обертаються навколо теми випадковості. Це в основному поле для гольфу з 9 отворами , але буде розкрито на кілька питань. Ви можете брати участь у будь-якому виклику індивідуально, ніби це було звичайним питанням.

Однак я буду підтримувати таблицю лідерів у всіх викликах. Серія матиме 9 викликів (поки що), один розміщений кожні кілька днів. Кожен користувач, який бере участь у всіх 9 викликах, має право виграти всю серію. Їх загальний бал - це сума їх найкоротших подань на кожен виклик (тому якщо ви відповісте на виклик двічі, до балу зараховується лише краща відповідь). Якщо хтось займає перше місце в цьому загальному лідері протягом 28 днів, я присуджую їм суму в 500 респ .

Хоча у мене є маса ідей, що вибудовуються для цієї серії, майбутні виклики ще не поставлені перед каменем. Якщо у вас є якісь пропозиції, будь ласка, повідомте мене про це у відповідній поштовій скриньці .

Отвір 1: Перемішати масив

Перше завдання досить просте: даючи не порожній масив цілих чисел, переміщуйте його випадковим чином. Однак є кілька правил:

  • Кожна можлива перестановка повинна повертатися з однаковою ймовірністю (тому перетасування має мати рівномірний розподіл). Ви можете перевірити, чи ваш алгоритм є рівномірним / неупередженим, застосувавши його в JavaScript на " Will it Shuffle" , який створить матрицю зміщення - результат повинен виглядати однаково, як їх вбудовані 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
Я розчарований, що нам не дозволяють бути "розумними" і використовувати функції бібліотеки, окрім "отримати випадкове число" . Ми хочемо переглянути ще 69 реалізацій перетасовки Fisher-Yates? Будь ласка, подумайте про видалення цього правила в майбутніх завданнях. Крім того, навіщо обмежувати часову складність? Подумайте про розслаблення його принаймні до O (n ^ 2); Я також думаю, що хтось може знайти особливо гольову реалізацію, якщо ви дозволите O (n!).
anatolyg

7
@anatolyg Усунення обмежень означає, що кожна відповідь є sortby(random)(причина часового обмеження) або просто .shuffle()(причина вбудованого обмеження), що, на мою думку, є набагато менш розумним, ніж необхідність втілити Fisher-Yates або якусь іншу підхід.
Мартін Ендер

1
Якщо перетасовка на місці, чи повинна функція повертати масив, чи достатньо, щоб вона була змінена? Чи можу я записати функцію shuffle(array)замість newArray=shuffle(array)?
Геобіт

1
@Bakuriu Стверджуючи, що ви можете сортувати за лінійним часом, якщо цифри фіксовані, трохи схоже на те, що ви можете зробити що-небудь в O (1), якщо розміри введення фіксовані. Також відповідним обмеженням є масиви фіксованого розміру, а не цілі числа фіксованого розміру - тому що розмір масиву визначає, наскільки великими вам потрібні випадкові числа. У будь-якому разі, обмеження на часову складність, звичайно, стосується загального алгоритму, який ви реалізуєте, тоді як обмеження на вхідні розміри встановлені, тому вам не доведеться використовувати цілі числа довільної точності, якщо ваша мова не використовує їх поза полем .
Мартін Ендер

2
Чому рішення Adám виходить як 43319 байт, коли насправді це 14?
boboquack

Відповіді:


20

Діалог 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
мову, яку я повинен читати справа наліво ?? Оце Так!
Світлий

5
@ Світло, як це часто трапляється з математичними позначеннями: sin cos ln sqrt x
ngn

4
@ngn, коли ви сказали це так, що робить мій попередній коментар схожим на сміх. га.
Світлий

5
@ronalchn Є 8-бітові кодування для APL, як цього одного або цього іншого; Я чув, що Dyalog використовує один із них як альтернативу Unicode.
anatolyg

12

80386 код машини, 44 24 байти

Шестнадцятковий код:

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для лайна і хихикань.
FUZxxl

@FUZxxl Я зовсім забув про це! Шкода, що це видаляє найцікавішу частину моєї відповіді ...
anatolyg

9

Ява, 88 101

Основний перемішання Фішера-Йейта виконує свою справу. Я відчуваю, що тут він буде використовуватися досить часто, оскільки це швидко та легко здійснити. Тут набивається певна петля / завдання, але, чесно кажучи, не дуже гольфу, багато; це лише короткий характер.

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()має розмір, який є потужністю два, тому це не відповідає специфікації.
Пітер Тейлор

1
Тлумачення @PeterTaylor Яна та Geobits насправді, як я задумав правило, - вам не потрібно турбуватися про фактичну тривалість циклу PRNG.
Мартін Ендер

1
@ MartinBüttner тривалість циклу тут не є проблемою - це стосується вашого правила. Грубість поплавків є.
Джон Дворак

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

Це функція, яка переміщує масив на місці, не повертаючи його, використовуючи пряму реалізацію перемикання Фішера-Йейта . Отримати випадкові числа з 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: Елемент з y індексу x.
  4. (<<<x) { y: Усі елементи, крім предмета в індексі xв y.
  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: цілі числа від 0доy - 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
Як тільки це з’ясується, я можу набагато більше шансів підтримати цю відповідь ;-)
Джон Дворак

@randomra Ось ви йдете.
FUZxxl

@JanDvorak Чи пояснення задовольняє?
FUZxxl

Чудове пояснення! Я не знав про все використання в коробці from( {). І мені дуже подобається &>/хитрість маніпулювати списком. Я впевнений, що міг би використати його кілька разів раніше.
randomra

5

Pyth, 25 байт

Перевірте це тут.

Ще одна реалізація Fisher-Yates. По суті те ж саме, що і @ Sp3000 python, просто в 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 дякую за пораду. Я знав, що, мабуть, був спосіб замінити значення в списку, і це справді розумно. Ви повинні додати його до списку порад.
Мальтісен

4

Перл, 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--}

Це мій перший кодегольф.


@_[...]Непоганий старт, я не знав, що ти можеш використовувати як таке значення. Можна подати в гольф далі 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];}

Просто пряма реалізація Фішера-Йейта, яка сортує даний масив на місці. Компіляції та посилання ідеально поєднуються з компілятором візуальної студії (vs2013, не перевіряли інші версії) та Intel Compiler. Приємно виглядає функція підпису s(int array[], int length). Я законно вражений, що переміг Пітона та Рубі.

Це припускає srand(), що викликається і rand () реалізовано належним чином, але я вважаю, що це правило дозволяє це:

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{, але я не впевнений і не хочу тестувати. Ви можете зробити xors-swap, як в a[i]^=a[m]^=a[i]^=a[m]. Це також уникає необхідності декларувати t.
FUZxxl

@FUZxxl Я вважаю, що xor своп викликає проблеми, якщо i==m.
Геобіт

@Geobits дійсно. Я пропустив таку можливість.
FUZxxl

Я просто намагався з'ясувати, чому це не працює ... мав би це пам’ятати. Також мені потрібні s(a,m)int*aвізуальна студія та компілятор Intel. Не встановлюйте gcc або clang для тестування, але я припускаю, що вони також скаржаться.
псевдонім117

Це досить вражаюче гольф. Спробувавши багато модифікацій, які нічого не врятували, мені вдалося побачити спосіб збереження 2 символів. Якщо ви зміните порядок заміни таким чином, що перший випадок swap стає 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" "end"!


1
Просто FYI, "байти" насправді не вимагається кодом, він просто переконується, що є заголовок, який містить кому (для відокремлення мови) та принаймні одне число після коми, а потім просто вибирає останню число, яке не перекреслено Маючи "байти" там все ще приємно. ;)
Мартін Ендер

1
Ви можете зберегти 1 байт, використовуючи numelзамість lenght. В якості бонусу ваша програма також буде працювати з 2-D масивами aka matrices;)
paul.oderso

2

Ява 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()?
Роулінг

1
@Rawling Ви можете проголосувати за це мета-питання . Наразі 9 голосів "за" лямбданів і 0 проти. Так, круглі дужки можна видалити.
feersum

Так, якщо є метапост і настільки далекий консенсус, тоді звільняйте. (І насолоджуйтесь двома нижчими
оцінками

3
Я думаю, це несправедливо, якщо функція зупиняється за винятком у звичайному випадку, чи не так?
Qwertiy

1
@Qwertiy До кожного свого ... Ти думаєш, що це несправедливо, я думаю, що це здорово.
feersum

2

Гольфлуа, 37

Як запустити Golflua?

~@i=1,#X`r=M.r(i)X[i],X[r]=X[r],X[i]$

Вхід подається у вигляді таблиці в змінній X. Таблиця переміщується на місці.

Приклад використання:

> X={0,-45,8,11,2}
> ~@i=1,#X`r=M.r(i)X[i],X[r]=X[r],X[i]$
> w(T.u(X))
-45 0 8 11 2

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

Матлаб, 67

Також реалізує Fisher-Yates.

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

Я думав, що це дуже погано, що я не міг використовувати randpermфункцію Матлаба . Але після декількох роздумів я подумав, що я можу подивитися на джерело, randpermщоб побачити, як це робиться, і я здивовано побачив, що існує лише один рядок: [~,p] = sort(rand(1,n))=)


2

Перл, 44

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

Ще один перл у 44 символи. Приклад використання:

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

2

Математика, 82 90 83 93 байт

Примітка. Ця зміна перемикання Фішера-Йейта - це насправді рішення Мартина Бюттнера, з деяким розбором коду алефалфа. 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.
алефальфа

2

Рубін, 57 байт

->a{a.size.times{|i|j=rand(i+1);a[i],a[j]=a[j],a[i]};p a}

Введення (як лямбда-функція):

f.([1,2,3,4,5])

Вихід:

[2, 1, 4, 3, 5]


2

К, 31 чол

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

Не зовсім такий короткий, як той, який я поставив раніше (який дискваліфікували) ... о добре.

Це базовий переміст Fisher-Yates. Це було побудовано з великою допомогою з списку розсилки Kona .


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 bytes

XH`HnYr&)XHxvHHn

Try it online!

Fisher-Yates in MATL. Almost a third of this program is devoted to the letter H, which corresponds to the clipboard function in MATL.

Basically, H stores the unused items from the input, while the stack keeps track of the shuffled list.


2

Japt, 12

rÈiMqZÄ Y}[]

Try it!

-10 (about half ;) thanks to @Shaggy!

I have been wanting to try out a golfing language, and the Japt interpreter had good documentation and a way to try things out in the browser.

Below is the strategy I took:

  • Reduce input seeding with an empty array
  • At each step, find a random slot to insert the current element

1
Welcome to Japt, good to have you with us. I think this works for 9 bytes, using the same method. If the RNG isn't satisfactory, though, then try this instead.
Shaggy

@Shaggy - Thanks for the tips! :) I ended up using a slightly modified version of your 2nd solution. Since the 3rd parameter of the reduce function is an index, we already know the length.
dana

1

Javascript ES6, 69

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

It's Fisher–Yates.

PS: Can be tested in Firefox


@MartinBüttner, removed it :)
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

Another Fisher-Yates solution inspired by the algorithm at https://wiki.haskell.org/Random_shuffle.

s is a function which has signature: IOArray Int a -> IO [a]


1

CJam - 30

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

Try it at http://cjam.aditsu.net/

Example input: [10 20 30 40 50]
Example output: 3020401050 (add a p at the end of the code for pretty printing)

If the code is allowed to take the input from the stack (like a function), then the first 2 characters can be removed, reducing the size to 28.

Explanation:

The code is longer than I hoped, due to the lack of a "swap" operator for arrays
(to be implemented later :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]

As mentioned in the comments, I'm afraid this is invalid. At the very least _ is O(N) (inside an O(N) loop). Unfortunately, I don't see a way to work around that in CJam.
Martin Ender

Lists are handled like immutable objects, so duplication is just implemented as duplicating the reference. It's actually the t that kills it, as it can't mutate the list and now must create a copy.
Runer112

@MartinBüttner I was about to post the same thing as Runer112; yes there might be a problem with t, I'd like to improve it in future versions..
aditsu

So this code follows the spirit of the question, but not the "letter", due to internal language implementation issues.
aditsu

1

JavaScript (ES 6), 61

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

You can test it here by just adding a line that says shuffle = S (Firefox only).


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

Expects input as space separated numbers. I can remove the headers and observation numbers from the output if you would like, but otherwise this is shorter.


What's _n in this?
Martin Ender

_n is the number of the current observation.
bmarks


1

SQF, 91 bytes

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

1
This is biased (see "swap (i <-> random)" on Will It Shuffle), but you can turn it into Fisher-Yates (which is unbiased) by replacing %x with %i.
Martin Ender

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.