Реалізація Богоссорта


29

Чи вирішити судоку занадто важко? Навіть жорстока версія? Ось вправа на кодування, яка трохи простіше. Я сподіваюсь. :-P

Напишіть найкоротшу функцію для реалізації богосорту. Зокрема, ваша функція повинна:

  • Візьміть масив (або його еквівалент) як вхідний
  • Перевірте, чи впорядковані її елементи; якщо так, поверніть масив
  • Якщо ні, перемістіть елементи та почніть знову

Виграє найкоротший запис. У випадку зв'язання надається перевагу функції, яка підтримує користувацький компаратор (та / або генератор псевдовипадкових чисел). Будь-які інші зв'язки вирішуються на користь попереднього подання.


Уточнення: Ви можете використовувати будь-який тип елементів, який хочете, якщо, звичайно, є якийсь спосіб їх замовити. Також перемішування повинно бути рівномірним; нічого з цього "я просто заскочую це і називаю перетасованим" бізнесом. :-)


Які типи елементів? int або рядки?
Олександру

@ Олександру: І це добре. Ви вибираєте.
Кріс Єстер-Янг

Додавання користувацького компаратора збільшить довжину коду, тому переможна запис не матиме спеціального компаратора. Я думаю, що розривати краватку не має сенсу.
Олександру

1
Можливо, що цей алгоритм може вийти з ладу при використанні генератора псевдовипадкових випадків. наприклад, коли довжина списку перевищує 2000, є 2000! стани для списку, який може перевищувати кількість внутрішніх станів PRng.
гніблер

2
Так, відповідна цитата з вікіпедії "Однак, якщо замість випадкового джерела використовується генератор псевдовипадкових чисел, він ніколи не може припинитися, оскільки вони виявляють тривалу циклічну поведінку".
гніблер

Відповіді:


8

APL (Діалог), 20

{⍵≡⍵[⍋⍵]:⍵⋄∇⍵[?⍨⍴⍵]}

Пояснення

аргумент (правильний)
⍵≡⍵[⍋⍵]: Перевіряє, чи відсортовано дорівнює самому
:⍵: Якщо так, то повертайтеся
∇⍵[?⍨⍴⍵]: Else, генеруйте масив від 1 до ⍴⍵(довжина ) у випадковому порядку, переупорядковуйте відповідно до цього ( ⍵[...]) та застосуйте до нього функцію ( )


Раптом переглянувши цю проблему і ...

APL (Діалог), 19

{∧/2≤/⍵:⍵⋄∇⍵[?⍨⍴⍵]}

Тільки що думка про сортування масиву в чеку робить його безглуздим (не кажучи про те, що Bogosort має сенс), більш точною реалізацією було б ∧/2≤/⍵, і це трапляється для зниження кількості знаків.


15

Перл 6: 23 символи

@s.=pick(*)until[<=] @s

1
Це функція в perl? Це добре виглядає :)
Eelvex

1
Якщо ви не знаєте, [<=]перевірте, чи список відсортовано:, [<=] (1, 2, 3,) == (1 <= 2 <= 3) == (1 <= 2) and (2 <= 3)і .pick(n)вибирає зі списку n випадкових елементів і .pick(*)дозволяє Perl вибирати всі елементи. use.perl.org/~masak/journal/40459
Ming-Tang

Це повинно бути Perl 6. Я ніколи не бачив pick, щоб раніше використовував, не кажучи вже про те [<=]. Де в документації це?
Містер Лама

@GigaWatt Це Perl 6 (а не Perl 5). []- це оператор скорочення, який приймає оператора між квадратними дужками. Наприклад, [<=] 1, 2, 3є 1 <= 2 <= 3(і так, ви робите такі діапазони в Perl 6). У цьому випадку використовується для визначення того, чи впорядковані елементи. .pick(*)метод перетасовує список ( pick(N)вибирає Nелементи зі списку). .=call метод і присвоює результат змінній. Щодо документації - ну, поки що існує лише специфікація Perl 6 - feather.perl6.nl/syn , але вона існує.
Конрад Боровський

7

APL (22)

{(⍳X←⍴⍵)≡⍋⍵:⍵⋄∇⍵[X?X]}

Використання:

    {(⍳X←⍴⍵)≡⍋⍵:⍵⋄∇⍵[X?X]} 3 2 1
1 2 3

Пояснення:

  • ⍋⍵: повертає індекси елементів у відсортованому порядку, так ⍋30 10 20дає2 1 3
  • (⍳X←⍴⍵)≡⍋⍵:⍵Збережіть довжину списку введення в X. Якщо діапазон [1..X]дорівнює відсортованому порядку індексу, список сортується, тому поверніть його.
  • ⋄∇⍵[X?X]: якщо це не так, повторіть з перетасованим масивом.

7

Рубін - 33 символи

g=->l{l.shuffle!!=l.sort ?redo:l}

1 char менше:g=proc{|l|0until l.sort==l.shuffle!}
AShelly

@AShelly, ваша версія не працює. Моя версія (на 5 символів менше) f=->l{l.sort!=l.shuffle!?redo:l}(Ruby 1.9)
Hauleth

хтось, будь ласка, пояснить мені, чому redoпрацює з, procале не в класичному методі def...end? Я думав, redoпрацює лише з петлями?
Патрік Осіті

1
Добре, що я не знайшов, я знайшов щось у книзі "Мова програмування Ruby": " redo[...] передає управління назад на початок проклейки чи лямбда". Просто так.
Патрік Осіті


5

J - 34 27

f=:({~?~@#)^:(1-(-:/:~))^:_

наприклад:

f 5 4 1 3 2
1 2 3 4 5

f 'hello'
ehllo

Частина {~? ~ @ # Переміщує вхід:

({~ ?~@#) 1 9 8 4
4 8 9 1
({~ ?~@#) 'abcd'
bdca

3

Пітон 61

Розбирається на місці.

import random
def f(l):
 while l!=sorted(l):random.shuffle(l)

Ваша функція не повертає масив успіху.
hallvabo

Розбирається на місці. Пройдений масив модифікований.
Олександру

Питання говорить про те, що функція повинна повертати масив - навіть якщо технічно це не потрібно для отримання результату.
Джонатан М Девіс

1
from random import*можна зберегти чару.
ugoren

1
Це може не завжди працювати: (з документації на випадковий модуль python): "Зауважте, що для навіть досить малого len (x) загальна кількість перестановок x більше, ніж період більшості генераторів випадкових чисел; це означає, що більшість перестановок довга послідовність ніколи не може бути створена. "
Метт

3

Пітон 94

from itertools import*
def f(a):return [x for x in permutations(a) if x==tuple(sorted(a))][0]

Інші відповіді python використовують random.shuffle (). У документації випадкового модуля пітона зазначено:

Зауважимо, що для навіть досить малого len (x) загальна кількість перестановок x більше, ніж період більшості генераторів випадкових чисел; це означає, що більшість перестановок довгої послідовності ніколи не може бути створена.


Замість цього робіть лямбда; Я думаю, це було б коротше. Також зауважте, що ви можете робити return[x...на відміну від return [x.... Те саме з permutations(a) if- могло бути permutations(a)if.
0WJYxW9FMN

lambda a: [x for x in __import__("itertools").permutations(a) if x==tuple(sorted(a))][0]це 88 байт
знаменитий1622

3

К, 31 25

{while[~x~x@<x;x:x@(-#x)?#x];x}

{x@(-#x)?#x}/[{~x~x@<x};]

.

k){x@(-#x)?#x}/[{~x~x@<x};] 3 9 5 6 7 9 1
`s#1 3 5 6 7 9 9

.

k){x@(-#x)?#x}/[{~x~x@<x};] "ascsasd"
`s#"aacdsss"

2

Пітон (69 символів)

from random import*
def f(a):
 while a>sorted(a):shuffle(a)
 return a

Сортує цілі числа у збільшенні числового порядку. Зауважимо, що рекурсивні рішення, як

from random import*;f=lambda a:a>sorted(a)and(shuffle(a)or f(a))or a

не вдасться через переповнення стека навіть для невеликих входів (скажімо, N> 5), оскільки Python не робить оптимізацію хвостових викликів.


2

D без спеціального компаратора: 59 символів

R f(R)(R r){while(!isSorted(r))r.randomShuffle();return r;}

Більш розбірливо:

R f(R)(R r)
{
    while(!r.isSorted)
        r.randomShuffle();

    return r;
}

D з користувацьким компаратором: 69 символів

R f(alias p,R)(R r){while(!isSorted!p(r))r.randomShuffle();return r;}

Більш розбірливо:

R f(alias p, R)(R r)
{
    while(!isSorted!p(r))
        r.randomShuffle();

    return r;
}

2

Скала 73:

def s(l:Seq[Int]):Seq[Int]=if(l==l.sorted)l else s(util.Random.shuffle l)

У Scala ми можемо перевірити, чи робив компілятор оптимізацію хвостових викликів:

@annotation.tailrec
def s(l:Seq[Int]):Seq[Int]=if(l==l.sorted)l else s(util.Random shuffle l)

і так, це було. Однак для короткого списку зі 100 значень:

val rList = (1 to 100).map(x=>r.nextInt (500))
s(rList) 

на це пішло майже 4 місяці. ;)


2

C # (184 символів)

T[]S<T>(T[]i)where T:IComparable<T>{T l=default(T);while(!i.All(e=>{var r=e.CompareTo(l)>=0;l=e;return r;})){i=i.OrderBy(a=>Guid.NewGuid()).ToArray();l=default(T);}return i.ToArray();}

Це не дуже приємно робити це в C #. Ви повинні підтримувати дженерики для підтримки як значення, так і типових типів. Немає функції перетасування масиву чи функції, яка б перевіряла, чи щось відсортовано.

Хтось має поради, щоб зробити це краще?

Редагувати версію, яка лише сортує int (134 символів):

int[]S(int[]i){var l=0;while(!i.All(e=>{var r=e>=l;l=e;return r;})){i=i.OrderBy(a=>Guid.NewGuid()).ToArray();l=0;}return i.ToArray();}

2

GNU / BASH 65

b(){ IFS=$'\n';echo "$*"|sort -C&&echo "$*"||b $(shuf -e "$@");}

Хм, чи можу я отримати спеціальний виняток із правила повернення масиву, оскільки функції bash можуть лише буквально повертати неподписаний байт?
kojiro

2

C ++ 11, 150 символів

#include<deque>
#include<algorithm>
void B(std::deque &A){while(!std::is_sorted(A.begin(),A.end())std::random_shuffle(myvector.begin(),myvector.end());}

Просто .. зроблений для розваги.


1
std :: random_shuffle не є рівномірним. У роз'ясненнях зазначається: "Крім того, переміщення повинно бути рівномірним"
STDQ

Гаразд ... я не знав, що це не рівномірно.

Він покладається на rand (), який не є рівномірним - див. Open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3924.pdf . Не багато інших людей, здається, слідкують, так що я думаю, це не велика справа.
STDQ

Отже, якщо я використовую повністю випадковий, як-от використання srand (time (0)), то чи враховується це?

Проблема полягає в тому, що rand не гарантує хорошої якості випадкових чисел, не кажучи вже про однорідність, деякі виробляють не випадкові біти низького порядку. Я думаю, це не має і не має значення в кінці кінців. Я отримав лише ще 8 байтів, використовуючи рівномірний розподільник зі std :: shuffle і так далі, досить добре для мене.
STDQ

2

Пітон - 61 символ

Рекурсивний

from random import*;f=lambda l:l==sorted(l)or shuffle(l)>f(l)

Ваша функція повертає значення True або False, а не масив.
hallvabo

2
Також зауважте, що рекурсивні рішення приречені на збій навіть за малих входів.
hallvabo

1
@hallvabo: Насправді я хочу написати схему рекурсивного рішення в схемі, що, звичайно, не вичерпує ваш стек.
Кріс Єстер-Янг

@hallvabo, Олександру вже зробив очевидне рішення Python, тому я просто збирався дещо інше. Звичайно, рекурсивне рішення - просто для розваги, а не для серйозного суперника
gnibbler

from random import*може бути коротшим.
0WJYxW9FMN

2

PowerShell , 85 82 56 55 52 байт

-26 байт завдяки пропозиціям mazzy
-1 байт завдяки AdmBorkBork
-3 байти завдяки mazzy

for($l=$args;"$l"-ne($l|sort)){$l=$l|sort{random}}$l

Спробуйте в Інтернеті!

PowerShell має порівняно дешеве порівняння масивів, вкладаючи їх у рядки та порівнюючи це.


2
Перемістіть paramініціалізацію в forініціалізацію, щоб зберегти байт -for($l=$args;
AdmBorkBork

1
приємно. -neвідкидає правого оператора на скалярний тип лівого оператора. Таким чином, ви можете зберегти кілька байт: Спробуйте в Інтернеті!
маззи

1

Символи Javascript 291

хв

function f(e){var t=[].concat(e).sort();t.e=function(e){var n=true;t.forEach(function(t,r){if(t!=e[r])n=false});return n};while(!t.e(e.sort(function(){return Math.floor(Math.random()*2)?1:-1}))){console.log(e)}return e}

ун-хв

function f(a) {
var b = [].concat(a).sort();
b.e = function (z) {
    var l = true;
    b.forEach(function (v, i) {
        if (v != z[i]) l = false;
    });
    return l
};
while (!b.e(a.sort(function () {
    return Math.floor(Math.random() * 2) ? 1 : -1;
}))) {
    console.log(a);
}
return a;
}

У мене є відчуття, що я говорив це раніше, але ви можете видалити всі var. Просто зробіть їх усіма неявними глобалами, це просто зробити код якомога коротшим.
gcampbell

1

Матлаб, 59 байт

Відносно прямий підхід:

x=input('');while~issorted(x);x=x(randperm(numel(x)));end;x

1

J, 22 байти

$:@({~?~@#)`]@.(-:/:~)

Це рекурсивна мовчазна монада з використанням порядку денного. Ось як це працює:

Нехай yбуде наш список. По-перше, дієслово праворуч від порядку денного -:/:~. Це дієслово люб’язно надано Leaky Nun . Він відповідає ( -:) тим, чи сортується вхід ( /:~) за допомогою монадичного гака. ( (f g) y = y f (g y)) Це повертає одиницю або нуль відповідно. Ліва сторона порядку денного - це заголовок з двох дієслів: праворуч дієслово тотожності ], а зліва - місце, де відбувається рекурсія. За питань порядку денного вибирає або особистість дієслова в позиції , 1якщо список буде відсортований, і більше дієслова в положенні , 0якщо список НЕ відсортований.

$:@({~?~@#)виклики $:(найдовше дієслово, яке воно міститься) вгорі результату {~?~@#на y. Це перетасовує список, оскільки ?~@#приймає перестановки довжини y, будучи випадковим чином відсортованими показниками y. {~, в монадійний гачок, повертає список y, індекси якого є правильним аргументом. Цей перетасований список знову викликається з порядок денним і повторюється, поки він не буде відсортований.


1

C ++ 14, 158 байт

#include <algorithm>
#include <random>
[](int*a,int s){std::random_device r;for(std::knuth_b g(r());!std::is_sorted(a,a+s);std::shuffle(a,a+s,g));return a;};

1

Желе , 6 байт, виклик мови після публікації

ẊŒ¿’$¿

Спробуйте в Інтернеті!

Пояснення

ẊŒ¿’$¿
     ¿  While
 Œ¿’$     the input is not in its earliest possible permutation (i.e. sorted)
Ẋ       shuffle it

Œ¿присвоює номер кожній перестановці списку; 1 відсортовано, 2 має два останні елементи, що обмінюються тощо, аж до фактора довжини списку (що є списком у зворотному порядку). Отже, для відсортованого списку це має значення 1, і ми можемо зменшити його за допомогою того, щоб створити "не відсортований" тест, який можна використовувати як булевий стан у певному режимі циклу. Це $полягає в тому, щоб умова розбиралася як група.


1

C ++, 166 байт

Мех.

#import<algorithm>
#import<random>
#define r b.begin(),b.end()
template<class v>
v f(v b){auto a=std::mt19937();while(!std::is_sorted(r))std::shuffle(r,a);return b;}

Це має працювати на всіх контейнерах STL, у яких є begin()і end().

Безголівки:

#include <algorithm>
#include <random>
template <class v>
v f(v b) {
    auto a = std::mt19937();
    while (!std::is_sorted(b.begin(),b.end()))
        std::shuffle(b.begin(),b.end(),a);

    return b;
}


1

Брахілог , 5 байт

∈&ṣ≤₁

Спробуйте в Інтернеті!

Коли я вперше побачив відповідь Brachylog від ais523 (на відміну від його відповіді Jelly, тому що якщо я не помиляюся, користувач 62131 був також ним), я задумався, а що, якщо він використовує зворотний трекінг замість рекурсії? Так спочатку я спробував ṣ≤₁. Виявляється, оскільки вибір чого-небудь навмання не дає декількох результатів настільки багато, скільки він просто дає один вихід недетерміновано, предикат перемикання не може бути відкликаний назад, тому запуск, який просто не вдасться, якщо вам не пощастить перетасувати його правильно з першої спроби. Після цього я спробував pṣ≤₁, що працював більшу частину часу, але оскільки у безперервно довгого списку є кінцево багато перестановок, він все-таки іноді провалювався випадково. Після відмови від мети досягти скорочення довжини я нарешті придумав таке:

         The input
∈        is an element of
         an unused implicit variable,
 &       and the input
  ṣ      shuffled randomly
   ≤₁    which is increasing
         is the output.

(Демонстрація випадковості)

Хоча насправді це може бути трохи коротше, якщо ми візьмемо деякі свободи з вводу / виводу ...

Брахілог , 4 байти

⊆ṣ≤₁

Спробуйте в Інтернеті!

Для того, щоб результат був корисним, вхід не повинен містити жодних повторюваних елементів, оскільки крім сортування вводу, цей предикат bogosort додає довільну кількість повторюваних елементів та нулів. (Гіпотетично це може додати що завгодно, але це просто не так.) Зазвичай я б не намагався згадувати щось таке, що далеко не належним чином функціонує, але я відчуваю це в дусі виклику.

⊆        An ordered superset of the input
 ṣ       shuffled randomly
  ≤₁     which is increasing
         is the output.

1

Perl 6 , 28 байт

{({.pick(*)}...~.sort).tail}

Спробуйте в Інтернеті!

Блок анонімного коду, який перетасовує список до його сортування. Зауважте, що він сортує список принаймні один раз, що дозволено. І ні, його {.pick(*)}неможливо замінити*.pick(*)


1

Pyth , 11 байт

Wn=Q.SQSQ;Q

Досить задоволений цим, напевно, можна пограти трохи більше в гольф

Пояснення


Wn=Q.SQSQ;Q
W    While
  =Q.SQ    Variable Q (input variable) shuffled 
 n  Does not equal
       SQ    Variable Q sorted
             ;  Do nothing (loop ends)
              Q    And output variable Q

Спробуйте в Інтернеті!


Ви можете скоротити =Q.SQдо =.SQ-1 байт (працює і з іншими операторами, наприклад =QhQ-> =hQ)
ar4093

1

Japt , 11 9 байт

_eZñ}a@öx

Спробуй це

_eZñ}a@öx     :Implicit input of array U
_             :Function taking an array as argument via parameter Z
 e            :  Test Z for equality with
  Zñ          :  Z sorted
    }         :End function
     a        :Repeat and return the first result that returns true
      @       :Run this function each time and pass the result to the first function
       öx     :  Random permutation of U

1

Брахілог (v2), 5 байт

≤₁|ṣ↰

Спробуйте в Інтернеті!

Подання функції (Посилання TIO використовує аргумент командного рядка, який автоматично перетворює функцію в повну програму.)

Пояснення

≤₁|ṣ↰
≤₁      Assert that {the input} is (nonstrictly) sorted in ascending order
  |     Output it
  |     Exception handler: if an assertion fails:
   ṣ      Randomly shuffle {the input}
    ↰     and run this function recursively on it, {outputting its output}

Prolog (мова, на яку збирається Брахілог) є хвостовим рекурсивним, тому ця функція в кінцевому підсумку збирається в тугий цикл.


0

C (203 символів, відсутність циклу введення: тільки функція)

#include <stdio.h>
#define P (int*a,int n){
#define F for(i=0;i<n;i++){
int i,j,v;s P F if(a[i]>a[i+1])return 0;}return 1;}void h P F v=a[i];a[i]=a[j=rand()%n];a[j]=v;}}void b P while(!s(a,n-1))h(a,n);}

Це те саме, що в наступному, де ми також читаємо масив зі stdin і виписуємо відсортований масив. Оскільки Q запитав функцію, а не всю програму ...

C (296 символів)

#include <stdio.h>
#define P (int*a,int n){
#define F for(i=0;i<n;i++){
int i,j,n,v,x[999];s P F if(a[i]>a[i+1])return 0;}return 1;}void h P F j=rand()%n;v=a[i];a[i]=a[j];a[j]=v;}}void b P while(!s(a,n-1))h(a,n);}main(){while(scanf("%d",&v)==1)x[n++]=v;if(!s(x,n))b(x,n);F printf("%d\n",x[i]);}}

Компіляція може подавати попередження (неявні декларації). Обмеження розміру масиву, затвердженого за допомогою жорсткого коду, становить 999 елементів. Тендітна.

якщо немає необхідності попередньо перевіряти, чи сортується масив, це можна зробити за допомогою 284.

C (251 символів, було 284)

#include <stdio.h>
#define F for(i=0;i<n;i++){
int i,j,n,v,a[999];s(int n){F if(a[i]>a[i+1])return 0;}return 1;}void h(){F v=a[i];a[i]=a[j=rand()%n];a[j]=v;}}void b(){while(!s(n-1))h();}main(){while(scanf("%d",&a[n++])>0);b();F printf("%d\n",a[i]);}}

(використання глобалів замість аргументів функції).

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