Осуществить сортировку сна


74

Sleep Sort - алгоритм целочисленной сортировки, который я нашел в Интернете. Он открывает выходной поток, и для каждого входного числа параллельно задерживается число секунд и выводится это число. Из-за задержек наибольшее число будет выведено последним. Я оцениваю это имеет O (n + m), где n - количество элементов, а m - наибольшее число.

Вот оригинальный код на Bash

#!/bin/bash
function f() {
    sleep "$1"
    echo "$1"
}
while [ -n "$1" ]
do
    f "$1" &
    shift
done
wait

Вот псевдокод

sleepsort(xs)
 output = []
 fork
   for parallel x in xs:
     sleep for x seconds
     append x to output
 wait until length(output) == length(xs)
 return output

Ваша задача - реализовать функцию Sleep Sort на выбранном вами языке программирования. Вы можете пренебречь любыми факторами параллелизма, такими как состояние гонки, и никогда не блокировать какие-либо общие ресурсы. Самый короткий код выигрывает. Определение функции учитывает длину кода.

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


3
Что имеет значение для длины? Полные программы, включая IO или просто соответствующую программу?
— Конрад Рудольф

8
Проблема с этим. В зависимости от порядка списка, вы можете не прочитать весь список до того, как будет напечатано первое значение. Например, большой список, для чтения которого требуется 45 секунд, первое значение равно 2, а последнее значение равно 1. Поток для печати 1 может быть выполнен после печати 2. К сожалению, выходные данные больше не сортируются должным образом. Могут быть некоторые обходные пути - создание потоков и их запуск после прочтения всего списка (но это приведет к увеличению длины кода по сравнению с гольфом). Интересно, может кто-нибудь предоставить гольф, который решит эту потенциальную проблему ... Я собираюсь попробовать.
— Томас Оуэнс

11
Кстати, что делает этот алгоритм действительно интересным, так это то, что на самом деле существуют реальные приложения. Например, секвенирование ДНК (секвенирование Сэнгера) зависит от чего-то подобного для сортировки фрагментов ДНК в соответствии с их длиной (и, в более общем случае, каждый электрофорез делает что-то подобное). Разница в том, что последовательность выполняется физически, а не на компьютере.
— Конрад Рудольф

12
Я ненавижу быть тем, кто идет на параде всех, но разве это не просто переложит сложность на планировщик ОС способом, который, вероятно, O (N ^ 2)?
— Random832

1
Я думаю, что есть алгоритмы физической сортировки, которые занимают O (n) времени, но O (n) физических объектов. Ну, мы можем использовать тающие свечи и трубку, чтобы сделать это. ru.wikipedia.org/wiki/Spaghetti_sort
— Мин-Тан,

Ответы:


17

Этакая неудачная попытка Perl , 59 55 52 38 32 персонажа :

map{fork||exit print sleep$_}@a

Barebones: 25 символов:

... если вы не возражаете против результатов сортировки:

map{fork||die sleep$_}@a

Со всеми отделками:

(для максимального соответствия требованиям, 44 символа)

sub t{map{fork||exit print sleep$_}@_;wait}

Если вы позволите Perl ждать вас, 39 символов:

sub t{map{fork||exit print sleep$_}@_}

И снова, если не возражаете die(), 32 символа ...

sub t{map{fork||die sleep$_}@_}

Обратите внимание, что в Perl 6, или когда объявлена ​​функция 'say', можно заменить printфункцию say, сохраняя символ в каждом экземпляре. Очевидно, что, поскольку dieоба завершают разветвленный процесс и записывают вывод, это остается самым коротким решением.


Вы можете запустить, perl-Eчтобы включить 5.010 функций, таких какsay
— mbx

(fork&&die sleep$_)for@aтоже работает
— malkaroee

20

C , 127 символов, довольно очевидное решение:

main(int c,char**v){
#pragma omp parallel for num_threads(c)
for(int i=1;i<c;++i){int x=atoi(v[i]);sleep(x);printf("%d ",x);}}

(Составлено gcc -std=c99 -fopenmp sort.cи игнорируется все предупреждения.)


4
Круто, я действительно должен изучить Opemp
— Нильс

Я бы назвал это 93 символами (без разбора командной строки и тому подобного), но впечатляет, что вы можете сделать это всего за 34 дополнительных символа в C!
— Рекс Керр

1
@KonradRudolph - Вы можете сохранить 6 байт , идущие в обратном направлении: for(;c>=0;--c){int x=atoi(v[c]);. Не уверен, что это разрешено.
— owacoder

15

Ruby 1.9, 32 символа

Как функция:

s=->a{a.map{|i|fork{p sleep i}}}

Если мы можем просто использовать предопределенную переменную, она сокращается до 25 символов:

a.map{|i|fork{p sleep i}}

1
Вы можете сохранить несколько символов с помощью Thread.new{p sleep i}распечатки вывода.
— Говард

@ Ховард: Хороший улов, спасибо!
— Вентеро

@ Ventero, я только изучаю Ruby, и я хотел бы знать, как вы будете запускать эту лямбда-функцию или, более конкретно, как вы вводите это. Можно ли запустить с IRB? Спасибо!
— Бен Хили

14

JavaScript , 65 символов (в зависимости от того, используете ли вы console.logили что-то еще для вывода результата)

a.map(function(v){setTimeout(function(){console.log(v)},v*1000)})

Предполагается, что aэто массив неотрицательных целых чисел, который map()существует в прототипе массива (JavaScript 1.6+).


1
Вероятно, вы можете сбрить два или даже три символа, умножив на 10 (или 9) вместо 1000, не ставя под угрозу правильность.
— Конрад Рудольф

12
Если одна секунда предназначена, чтобы остаться, вы можете использовать 1e3вместо этого.
— Джои

2
@Tomalak alert- блокирующий вывод promptJavaScript, блокирующий ввод confirmJavaScript и блокирующий двоичный ввод JavaScript. Если бы JS записывался в командной строке, это были бы вызовы, которые вы бы использовали.
— zzzzBov

1
@zzzzBov, использование блокирования вывода почти наверняка будет плохой идеей для этой задачи.
— Питер Тейлор

2
@zzzzBov, я беспокоюсь о том, в каком порядке они называются, если только у спецификации JS нет строгих гарантий порядка, в котором вызываются thunks, поставленные в setTimeout.
— Питер Тейлор

13

APL ( 15 13)

{⎕←⍵⊣⎕DL⍵}&¨⎕

Что оно делает:

¨⎕       : for each element of the input
&        : do on a separate thread
⎕DL⍵    : wait approx. ⍵ seconds
⎕←⍵     : output ⍵

Я вижу коробки вместо 3 символов.
— defhlt

8
@ArtemIce: там должно быть три коробки (четырехугольника). Два - переменная ввода / вывода (чтение, которое получает вход, и запись в него, печатает вывод), и одно находится в названии ⎕DLфункции, которая является sleep.
— marinus

9

Четыре попытки в Эрланге:

Вывод на консоль позволил себе сделать это каждый, 9ms * Numberпоскольку этого достаточно, чтобы заставить его работать (протестировано на встроенной плате Atom = медленно):

Нужно 60 символов

s(L)->[spawn(fun()->timer:sleep(9*X),io:write(X)end)||X<-L].

Вывод на консоль полный не-Erlangish, поэтому Pвместо этого мы отправляем сообщение для обработки :

Необходимо 55 символов

s(P,L)->[spawn(fun()->timer:sleep(9*X),P!X end)||X<-L].

Отправка через некоторое время также может быть выполнена по-другому (это работает даже с 1ms * Number):

Требуется 41 символ

s(P,L)->[erlang:send_after(X,P,X)||X<-L].

На самом деле это немного несправедливо, поскольку встроенная функция send_afterзапаздывает и требует erlang:префикса пространства имен , если мы считаем это пространство имен импортированным (сделано на уровне модуля):

Необходимо 34 символа

s(P,L)->[send_after(X,P,X)||X<-L].

7

C # - 137 символов

Вот ответ в C # (обновленный со степенями параллелизма как прокомментировано)

void ss(int[]xs){xs.AsParallel().WithDegreeOfParallelism(xs.Length).Select(x=>{Thread.Sleep(x);return x;}).ForAll(Console.WriteLine);}

1
Вам нужно будет указать, WithDegreeOfParallelismчтобы это работало, аналогично тому, как num_threadsв моем коде OpenMP C.
— Конрад Рудольф

120 байтов:void m(int[] l){foreach(var i in l){var t=new Thread(()=>{Thread.Sleep(int.Parse(s));Console.Write(s);});t.Start();}}}
— MrPaulch

@MrPaulch Обратите внимание, что вам нужно снова присоединиться к потокам, если вы хотите, чтобы ваша программа
— еще один Geek

Почему? Самая длинная нить будет поддерживать процесс.
— MrPaulch

7

Питон - 81 93 148 150 153

Настройка кода @ BiggAl, так как это игра, в которую мы играем ....

import threading as t,sys
for a in sys.argv[1:]:t.Timer(int(a),print,[a]).start()

... или 97 175 с отложенным началом резьбы

import threading as t,sys
for x in [t.Timer(int(a),print,[a]) for a in sys.argv[1:]]:x.start()

Принимает ввод через командную строку, аля

./sleep-sort\ v0.py 1 7 5 2 21 15 4 3 8

Как и во многих питон-гольфах, наступает момент, когда код достаточно компактен, чтобы псевдонимы переменных для сокращения имен даже не сохраняли символы.

Хотя это и забавно, потому что он псевдоним sys и создает потоки ОБА как t, поэтому sys.argv становится t.argv. Короче, чем от импорта foo *, и чистая экономия символов! Однако я полагаю, что Гвидо не будет доволен ...

Примечание для самостоятельного изучения c и прекращения игры в гольф на питоне. СВЯТАЯ КОРОВА, ЭТО МЕНЬШЕ, ЧЕМ РЕШЕНИЕ C!


Мне удалось внести некоторые изменения, но форматирование не очень хорошо отображается в комментариях, поэтому я сделал свой собственный ответ. daemonне требует настройки, если вы не запускаете это как демон, и короче использовать позиционные аргументы, esp. если вы псевдоним NoneнаN
— theheadofabroom

Да, и первый не работает для меня под 2.7.1, как jкажется, Falseпобочным эффектом попытки сделать слишком много в одной строке?
— глава

дерьмо, я не осознавал, что вы можете импортировать несколько модулей в один и тот же псевдоним - я мог бы подумать о некоторых случаях использования для этого, когда у меня есть несколько подклассов одного и того же пользовательского базового класса, лежащих в отдельных подмодулях. Если мы сможем сбрить еще 30, это короче, чем bash ... Но я не думаю, что это произойдет.
— головной убор

Да, причина, по которой я не знал, в том, что вы не можете - я просто попытался запустить его, а многопоточность - это не псевдоним, а просто поточная. Это системный псевдоним T ... Вы пытались запустить это? Это только дополнительные 2 символа на каждого, хотя их нужно импортировать, as t,sа затем изменить sнаsys
— theheadofabroom

1
почему вы не используете printфункцию вместо sys.stdout.write?
— летающая овца

6

Для забавы, вот версия ColdFusion (8+) ;-) В ней 109 символов, не считая переносы строк и отступы, которые я добавил для удобочитаемости здесь.

<cfloop array="#a#" index="v">
  <cfthread><cfthread action="sleep" duration="#v*1000#"/>#v#</cfthread>
</cfloop>

Это предполагает, что <cfoutput>это в силе. Несколько символов можно сохранить, написав все в одной строке.


6

Ява (иначе никогда не выигрывает в Codegolf): 234 211 187 символов

public class M{public static void main(String[]s){for(final String a:s)new Thread(){public void run(){try{sleep(Long.parseLong(a));}catch(Exception e){}System.out.println(a);}}.start();}}

ungolfed:

public class M {
    public static void main(String[] s) {
        for(final String a:s) new Thread(){
            public void run() {
                try {
                    sleep(Long.parseLong(a));
                } catch(Exception e){}
                System.out.println(a);
            }
        }.start();
    }
}

@ Джои, спасибо за то, что поправил.
— Истина

Класс может быть закрытым, сохраняя 7 символов.
— Даниэль Любаров

1
Вы также можете объявить throws Throwableи избавиться от catchоговорки.
— Даниэль Любаров

Я думаю, что вы можете сохранить 2 байта, заменив Long.parseLongна Long.valueOf.
— HyperNeutrino

Я знаю, что прошло 6,5 лет, но вы можете играть в гольф некоторыми частями: publicи finalмогут быть удалены; class M{public static void mainможет быть interface M{static void main(Java 8+); Long.parseLong(a)может быть new Long(a)(в результате получается 165 байтов )
— Кевин Круйссен

5

Javascript - 52 символа

for(i in a)setTimeout("console.log("+a[i]+")",a[i])

Добро пожаловать в CodeGolf.SE! Я отформатировал ваш ответ для вас, в частности выделив ваш код четырьмя пробелами, чтобы он отображался как код. Вы найдете другую справку по форматированию на боковой панели страницы редактирования.
— dmckee

5

Скала - 42 40 символов (особый случай)

Если у вас есть пул потоков, по крайней мере, размер числа элементов списка:

a.par.map{i=>Thread.sleep(i);println(i)}

Скала - 72 символа (общее)

a.map(i=>new Thread{override def run{Thread.sleep(i);println(i)}}.start)

afaik вы не используете, {}оставаясь на одной линии.
— летающая овца

@ Летающая овца - Вы можете опустить {}одно утверждение , но оно все равно необходимо для группировки вещей, разделенных ;одной строкой или нет. И {}в некоторых случаях вы можете писать многострочные операторы (например, если / еще).
— Рекс Керр

о, я не имел в виду, что вы можете опустить их, но ()вместо этого вы можете использовать их для однострочников. это вопрос вкуса, я думаю. (я просто не понимаю, почему ()вообще поддерживается, когда {}их заменяют. возможно, чтобы не отталкивать пользователей java мгновенно). Scala - это круто, но определение блоков кода с помощью отступов явно лучше. (и так начинается религиозная война;))
— летающие овцы

@ Летающие овцы - Вы дезинформированы. Вы можете использовать ()для отдельных заявлений. Попробуйте войти (1 to 9).map(i => {val j = i+1; i*j})в REPL и посмотрите, что произойдет, если вы используете (1 to 9).map(i => (val j = i+1; i*j)).
— Рекс Керр

правда, но я ссылался только на выражения и прочее. Извините, я ненавижу писать вещи, не имея возможности использовать переносы строк;)
— летающая овца

4

Хаскель - 143 персонажа

import Control.Concurrent
import System
d=threadDelay
f x=d(10^6*x)>>print x
g s=mapM(forkIO.f)s>>d(10^6*maximum s+1)
main=getArgs>>=g.map read

Вероятно, это можно было бы сделать короче, приняв ввод в stdin, если бы это была опция, но уже поздно, и в любом случае, для самой функции это все еще 104 символа.


4

Befunge-98, 38 31 байт

Я знаю, что это старая проблема, но я недавно обнаружил как спящие, так и двумерные языки, подумал о том, как их объединить, и искал место для его публикации, так что мы здесь.

&#vt6j@p12<'
v:^ >$.@
>:!#^_1-

Основной IP-адрес читает число ( &), а затем обращается к тому, tкто его клонирует: один переходит на ту же строку и циклически повторяет, считывает новые числа и генерирует новые дочерние элементы, пока не достигнет EOF, который завершает последовательность. Все дочерние процессы застревают в замкнутом цикле ( vи ^в третьем столбце) до тех пор, пока основной IP не завершит чтение ввода и не выполнит последовательность команд '<21p, которая переводит символ <в положение (1,2), перезаписывает ^и освобождает все дочерние процессы, которые начинают одновременно цикл, уменьшая на 1 их число на каждой итерации. Так как скорость выполнения различных IP-адресов синхронизируется в befunge, они будут завершаться (и печатать свои значения) по порядку, сортируя входной список.


26 байтов , немного перемещая поток управления.
— Джо Кинг,

3

Немного опоздал на вечеринку:

Клен - 91 83 символа

В 91:

M:=():use Threads in p:=proc(n)Sleep(n);:-M:=M,n;end:Wait(map(i->Create(p(i)),L)[])end:[M];

В 83:

M:=():use Threads in Wait(seq(Create(proc(n)Sleep(n);:-M:=M,n end(i)),i=L))end:[M];

(Для этого требуется версия Maple 15 и ожидается, что список будет отсортирован в L)


3

C 70 69 символов

Не ждет возврата дочерних процессов, иначе работает.

main(n) {
    while(~scanf("%d",&n)?fork()||!printf("%d\n",n,sleep(n)):0);
}

2

PHP 57 байт

<?for(;$i=fgets(STDIN);)pcntl_fork()?:die($i.usleep($i));

pcntl_fork () доступен только в Linux.


2

Баш (38):

xargs -P0 -n1 sh -c 'sleep $0;echo $0'

Изменить: Плавающая точка от стандартного ввода, разделенных пробелами или переводами строки.


2

Хаскелл, 90

import Control.Concurrent
s::[Int]->IO()
s=mapM_(\x->forkIO$threadDelay(x*9999)>>print x)

Я надеюсь, что это соответствует всем требованиям.



1

Просто некоторые изменения из версии @rmckenzie:

Python отложил начало потока в 155 152 114 108 107:

import sys, threading as t
for x in [t.Timer(int(a),sys.stdout.write,[a]) for a in sys.argv[1:]]:x.start()

Python без задержки в 130 128 96 95 93:

import sys,threading as t
for a in sys.argv[1:]:t.Timer(int(a),sys.stdout.write,[a]).start()

Управлял еще несколькими оптимизациями, используя Timerвместо Threadнего более лаконичный вызов и устранял необходимость в импорте time. Метод запуска с отложенным потоком выигрывает от понимания списка, так как устраняет необходимость отдельно инициализировать список в начале, хотя он на два символа длиннее ( "["+"]"+" "-":"), чем цикл for, поэтому он бесполезен без отложенного запуска, и вы должны быть осторожны при использовании списка а не генератор, или вы фактически не создаете потоки таймера, пока не разберетесь с генератором.

У кого-нибудь еще есть оптимизация?


Трюк с asподсказками, но в 2.7.1 вы можете импортировать только один модуль в псевдоним, и после некоторой игры с ним вы даже не сможете import mod1,mod2 as a,b, вы должны это сделать import mod1 as a, mod2 as b. Он по-прежнему сохраняет несколько символов, но это не совсем лекарство - все, о чем я думал ... И на самом деле лучше оставить sys в качестве sys. Псевдоним потоков все еще помогает, хотя ...


Вы меня били, есть апдинг. Мне нравится х = []; х + = []. Не знал, что вы могли бы сделать это ....
— arrdem

... вы могли бы сделать это в 128, если бы вы потеряли пробелы между: [оператор] в вашем цикле и f (x) ... каким-то образом я получил его до 127, но я думаю, что это не считая заключительный перевод строки (который законно в CG). Думаю, я бы дал вам обновление, а не инструмент и кражу вашего кода.
— arrdem

@rmckenzie пойти на это, я украл твой. Мне всегда интересно видеть CG'd Python - я чувствую, что делаю что-то очень извращенное, учитывая цели языка ...
— theheadofabroom

Да, я, честно говоря, шокирован тем, как разборчиво большинство питоновских гольфов остаются ... ценой "стеклянного пола" персонажей. Проверьте это: импортируйте потоки, sys as t
— arrdem

1

Clojure, 54

(defn s[n](doseq[i n](future(Thread/sleep i)(prn i))))


Вы можете избавиться от нескольких символов, вставив пропуск defn(его скобки + список аргументов: от 54 до 43 chrs), или использовать fnвместо defn=> len- = 2, так что я бы сказал в clj его 43: D
— test30

1

Ржавчина - 150 байт

И именно поэтому вы не пишете гольф в Rust, он более многословен, чем Java;). Зависит от внешнего ящика crossbeam, было бы еще хуже без него.

|x|{extern crate crossbeam;crossbeam::scope(|s|for&v in x{s.spawn(move||{std::thread::sleep(std::time::Duration::from_secs(v));println!("{}",v)});})}

Полная тестовая программа:

fn main() {
    let z =
    |x|{extern crate crossbeam;crossbeam::scope(|s|for&v in x{s.spawn(move||{std::thread::sleep(std::time::Duration::from_secs(v));println!("{}",v)});})}
    ;
    z(&[4, 2, 3, 5, 7, 8, 9, 1, 6, 10])
}

0

Скучно, порт C #, просто чтобы снова начать работать с языком:

F # - 90 символов

PSeq.withDegreeOfParallelism a.Length a|>PSeq.iter(fun x->Thread.Sleep(x);printfn "%A" x)

0

JavaScript, 74

function(a){for(i=0;i<a.length;i++)setTimeout('alert('+a[i]+')',a[i]*1e3)}

или 71/65 символов с нестандартностью:

function(a){a.map(function(v){setTimeout('console.log('+v+')',v*1e3)})}

Я думаю, что даже в 2011 году, function(a){a.map(function(v){setTimeout(console.log,v,v)})}по крайней мере, в одном браузере работало по 60 байт. Конечно, в эти дни вы бы написали a=>a.map(v=>setTimeout(console.log,v,v))вместо.
— Нил


0

VB.NET 100 байт

Поскольку VB.Net требует, чтобы однострочные лямбды содержали только одну инструкцию, этот код должен иметь несколько строк:

Array.ForEach(i, Async Sub(x)
Await Threading.Tasks.Task.Delay(x*1000)
Console.WriteLine(x)
End Sub)

Ungolfed:

Option Strict Off

Sub Main(i() as String)
    Array.ForEach(i, Async Sub(x)
                         Await Threading.Tasks.Task.Delay(x * 1000)
                         Console.WriteLine(x)
                     End Sub)
End Sub

Однако я не уверен, что вы подсчитываете операторы импорта в счетчиках байтов, потому что, если вы их не учитываете, я мог бы написать так:

VB.NET 71 байт

a.ForEach(i, Async Sub(x)
Await t.Delay(x*1000)
c.WriteLine(x)
End Sub)

Ungolfed:

Option Strict Off
Imports t = System.Threading.Tasks.Task
Imports c = System.Console
Imports a = System.Array

Sub Main(i() as String)
    a.ForEach(i, Async Sub(x)
                     Await t.Delay(x * 1000)
                     c.WriteLine(x)
                 End Sub)
End Sub

0

Groovy, 47 байтов

Предполагается, что номера приведены в командной строке ...

args.each{i->Thread.start{sleep(i*22)print i}}


0

Mathematica, 34 или 36 байт

RunScheduledTask[Print@#,{#,1}]&/@

Просто добавьте список к концу этого кода и оцените. Если оно должно быть допустимым определением функции, тогда требуется два дополнительных байта:

RunScheduledTask[Print@#,{#,1}]&/@#&

0

C ++ 11, 229 байт

#import<future>
#import<iostream>
using namespace std;int main(int a,char**v){auto G=new future<void>[a];while(--a){G[a]=move(async([=](){this_thread::sleep_for(chrono::seconds(atoi(v[a])));cout<<v[a]<<" "<<flush;}));}delete[]G;}

Ungolfed и использование:

#import<future>
#import<iostream>
using namespace std;
int main(int a,char**v){
 auto G=new future<void>[a];
 while(--a){
  G[a]=move(async(
   [=](){
    this_thread::sleep_for(chrono::seconds(atoi(v[a])));
    cout<<v[a]<<" "<<flush;
   }
  ));
 }
 delete[]G;
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.