Реализовать Богосорт


29

Является ли решение судоку слишком сложно? Даже версия грубой силы ? Вот упражнение по кодированию, которое немного проще. Я надеюсь. :-П

Напишите самую короткую функцию для реализации bogosort. В частности, ваша функция должна:

  • Возьмите массив (или эквивалент вашего языка) в качестве ввода
  • Проверьте, находятся ли его элементы в отсортированном порядке; если это так, вернуть массив
  • Если нет, перетасуйте элементы и начните снова

Самый короткий вход побеждает. В случае связи предпочтительнее использовать функцию, которая поддерживает пользовательский компаратор (и / или генератор псевдослучайных чисел). Любые оставшиеся связи решаются в пользу более раннего представления.


Пояснения: Вы можете использовать любой тип элемента, если хотите, если, конечно, есть какой-то способ их заказать. Кроме того, перетасовка должна быть равномерной; ничего из этого «я просто быстро сортирую и назову это перетасованным» бизнесом. :-)


Какие типы элементов? int или строки?
Александру

@Alexandru: Либо в порядке. Твой выбор.
Крис Джестер-Янг

Добавление пользовательского компаратора увеличит длину кода, поэтому в выигрышной записи не будет пользовательского компаратора. Я думаю, что разрывать галстук не имеет смысла.
Александру

1
Возможно, что этот алгоритм может не работать при использовании генератора псевдослучайных данных. например, когда длина списка превышает, скажем, 2000, есть 2000! состояния для списка, которые могут превышать количество внутренних состояний prng.
gnibbler

2
Да, соответствующая цитата из Википедии: «Однако, если вместо случайного источника используется генератор псевдослучайных чисел, он может никогда не завершиться, поскольку они демонстрируют длительное циклическое поведение».
Гнибблер

Ответы:


8

APL (Дьялог), 20

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

объяснение

является (правым) аргументом
⍵≡⍵[⍋⍵]: Проверяет, равна ли сортируемая величина самому себе
:⍵: Если да, то возвращает
∇⍵[?⍨⍴⍵]: Иначе, генерирует массив от 1 до ⍴⍵(длина ) в случайном порядке, переупорядочивает в соответствии с этим ( ⍵[...]) и применяет функцию к нему ( )


Внезапно вернуться к этой проблеме и ...

APL (Дьялог), 19

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

Просто мысль о сортировке массива в проверке делает его бессмысленным (не говоря о том, что Bogosort имеет смысл), более точная реализация будет ∧/2≤/⍵, и это приведет к снижению количества символов.


15

Perl 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
Минг-Тан

Это должно быть Perl 6. Я никогда не видел pickраньше, не говоря уже о [<=]. Где в документации те?
Мистер Лама

@GigaWatt Это Perl 6 (не Perl 5). []это оператор сокращения, который переводит оператор в квадратные скобки. Например, [<=] 1, 2, 3есть 1 <= 2 <= 3(и да, вы делаете такие диапазоны в Perl 6). В этом случае он используется для определения порядка элементов. .pick(*)метод перемешивает список ( pick(N)выбирает Nэлементы из списка). .=вызывает метод и присваивает результат переменной. Что касается документации - на данный момент существует только спецификация 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 символ меньше: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[…] передает управление обратно в начало процесса или лямбды». Это просто так.
Патрик Осцити

6

Математика , 40 37

NestWhile[RandomSample,#,Sort@#!=#&]&

С пробелами:

NestWhile[RandomSample, #, Sort@# != # &] &

Если вы игнорируете ошибки, вы можете сохранить три байта с помощью:#//.l_/;Sort@l!=l:>RandomSample@l&
Martin Ender

13 байт в Mthmca.
Майкл Стерн

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

Python 61

Сортировка на месте.

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

Ваша функция не возвращает массив в случае успеха.
Hallvabo

Сортировка на месте. Переданный массив модифицируется.
Александру

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

1
from random import*может сохранить символ
Угорен

1
Это может не всегда работать: (из документации модуля Python для случайных чисел): «Обратите внимание, что даже для довольно небольшого len (x) общее число перестановок x больше, чем период большинства генераторов случайных чисел; это означает, что большинство перестановок длинная последовательность никогда не может быть сгенерирована ".
Мэтт

3

Python 94

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

Другие ответы Python используют random.shuffle (). Документация случайного модуля Python гласит:

Обратите внимание, что даже для довольно небольших 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

Python (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 могут буквально возвращать только неподписанный байт?
Кодзиро

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: На самом деле я хочу написать хвостовое рекурсивное решение в Scheme, которое, конечно, не истощит ваш стек.
Крис Джестер-Янг

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

У меня такое чувство, что я говорил это раньше, но вы можете удалить все vars. Просто сделайте их неявными глобальными переменными, просто код будет максимально коротким.
gcampbell

1

Matlab, 59 байт

Относительно прямой подход:

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

1

J, 22 байта

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

Это рекурсивная, молчаливая монада, использующая повестку дня. Вот как это работает:

Позвольте yбыть нашим списком. Во-первых, глагол справа от повестки дня -:/:~. Этот глагол любезно предоставлен Лики Нун . Он соответствует ( -:) независимо от того, отсортирован ли ввод ( /:~) с использованием монадического хука. ( (f g) y = y f (g y)) Это возвращает один или ноль соответственно. Левая часть повестки дня представляет собой герунду из двух глаголов: справа - глагол тождества ], а слева - место, где происходит рекурсия. По вопросам повестки дня выбирает либо личность глагола в позиции , 1если список будет отсортирован, и больше глагола в положении , 0если список не отсортирован.

$:@({~?~@#)звонки $:(самый длинный глагол, в котором он содержится) поверх результата {~?~@#on 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, и мы можем уменьшить его, используя для создания «не отсортированного» теста, который можно использовать в качестве логического значения в условии цикла while. Это $вызывает условие для анализа в группе.


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().

Ungolfed:

#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, потому что, если я не ошибаюсь, user62131 также был им), я подумал: а что, если вместо рекурсии будет использоваться возврат назад? Итак, сначала я попробовал ṣ≤₁. Оказывается, поскольку случайный выбор чего-либо не приводит к множественным выводам, а только к тому, что один вывод недетерминированно, к предикату шаффла нельзя вернуться, поэтому запуск, который просто не удастся, если вам не повезет правильно перетасовать его с первой попытки. После этого я попробовал pṣ≤₁, что сработало большую часть времени, но, поскольку конечный длинный список содержит конечное число перестановок, иногда он по-прежнему терпел неудачу. После того как я отказался от цели сокращения длины, я наконец-то придумал:

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

(Демонстрация случайности)

Хотя на самом деле это может быть немного короче, если мы возьмем некоторые свободы с I / O ...

Брахилог , 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

Brachylog (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 (язык, на котором компилируется Brachylog) является хвостово-рекурсивным, поэтому эта функция в конечном итоге компилируется в узкий цикл.


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 попросил функцию, а не целую программу ...

С (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]);}}

Компиляция может дать предупреждение (неявные объявления). Ограничение размера массива Hardencoded 999 элементов. Хрупкое.

если нет необходимости предварительно проверять, отсортирован ли массив, это можно сделать в 284.

С (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.