Реалізуйте режим сну


74

Сонний сортування - це цілий алгоритм сортування, який я знайшов в Інтернеті. Він відкриває вихідний потік і паралельно для кожного вхідного числа затримується на число секунд і виводить це число. Через затримки найвища кількість буде виведена останньою. Я вважаю, що він має 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)?
Випадково832

1
Я думаю, що існують алгоритми фізичного сортування, які займають час O (n), але O (n) фізичні об'єкти. Що ж, ми можемо використовувати плавильні свічки та трубочку для цього. en.wikipedia.org/wiki/Spaghetti_sort
Мінг-Тан

Відповіді:


17

Своєрідна кульгава спроба Perl , 59 55 52 38 32 символів :

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

Баребони: 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, або коли «говорять» функція оголошена, то можна замінити 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

Рубін 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}для друку вихід.
Говард

@Howard: Добрий улов, дякую!
Вентеро

@ Вентеро, я лише вивчаю Рубі, і я хотів би знати, як ти запускатимеш цю лямбда-функцію або, точніше, як ти вводиш цю інформацію. Чи можна запускати 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натомість.
Joey

2
@Tomalak, alertблокуючий вихід promptJavaScript, є блокуючим входом confirmJavaScript і блокує двійковий вхід JavaScript. Якби JS був записаний у командному рядку, це були б дзвінки, які ви використовували б.
zzzzBov

1
@zzzzBov, використання блокування виводу майже напевно було б поганою ідеєю для цього завдання.
Пітер Тейлор

2
@zzzzBov - це той порядок, в якому вони називаються, про що я переживаю - якщо тільки специфікація JS не має чітких гарантій щодо порядку, в якому закликаються громи, що задаються TimeTimeout.
Пітер Тейлор

13

APL ( 15 13)

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

Що це робить:

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

Я бачу поля замість 3 символів.
дефш

8
@ArtemIce: Передбачається, що це три коробки (квадратики). Два - це змінна введення / виведення (читання вона отримує введення, а записування до неї друкує вихід), а одна - у назві ⎕DLфункції, яка є сном.
marinus

9

Чотири спроби в Ерланге:

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

Потрібно 60 символів

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

Вихід на консоль є загальним без ерлангського, тому ми надсилаємо повідомлення на обробку 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 Зверніть увагу , що вам потрібно знову приєднатися до нитки, якщо ви хочете , щоб ваша програма мати очікуване поведінка
Ще один майстер

Чому? Найдовша нитка збереже процес живим.
MrPaulch

7

Пітон - 81 93 148 150 153

Tweaking @ 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 і нанизує BOTH як t, тому sys.argv стає t.argv. Коротше, ніж від імпорту foo *, і економія чистого символу! Однак, гадаю, Гвідо не сподобається ...

Зауважте, щоб самостійно вивчити c та зупинити гольф у пітон. СВЯТА КОРОЦЬ ЦЕ БУДЬШЕ, ніж С РІШЕННЯ!


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

О, і перший не працює для мене під 2.7.1, як jздається, що це False- побічний ефект від спроби зробити занадто багато в одному рядку?
theheadofabroom

лайно, я не розумів, що ти можеш імпортувати кілька модулів в один і той же псевдонім - я насправді міг придумати деякі можливості для того, де у мене є кілька підкласів одного і того ж призначеного базового класу, що лежать в окремих модулях. Якщо ми зможемо поголити ще 30, це коротше, ніж баш ... Але я не думаю, що це станеться.
theheadofabroom

Причини, чому я не знав, це те, що ви не можете - я просто спробував запустити його, і нарізання різьби не зводиться, це просто називається нарізка. Це sys, який є псевдонім 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

Java (він ніколи не виграє в 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();}}

неозорений:

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

@Joey спасибі за те, що ви його встановили прямо.
trutheality

Клас може бути непублічним, заощаджуючи 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

Scala - 42 40 символів (спеціальний кейс)

Якщо у вас є пул потоків, принаймні розмір кількості елементів списку:

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

Scala - 72 символи (загальна)

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

afaik, яким ви не користуєтесь, {}перебуваючи на одній лінії.
літаючі вівці

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

о, я не мав на увазі, що ви можете їх опустити, але ви можете використовувати їх ()для одноклассників. це питання смаку, я думаю. (Я просто не отримую, чому їх ()взагалі підтримують, коли {}їх замінюють. Можливо, щоб миттєво не відчужувати користувачів Java). Скала класна, але визначення кодових блоків за допомогою відступу явно перевершує. (і так, настає релігійна війна;))
літаючі вівці

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

правда, але я посилався лише на вирази та речі. Вибачте, я ненавиджу писати речі без можливості користуватися рядками;)
літаючі вівці

4

Haskell - 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 байт

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

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

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


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'

Редагувати: плаваюча точка від stdin, розділена пробілами чи новими рядками.


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

Пітон без затримки в 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. Знизування різьби все ще допомагає ...


ти мене побив, мав настрій. Мені подобається x = []; x + = []. Не знав, що ти можеш це зробити ....
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)

Безголівки:

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)

Безголівки:

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

Безголовка та використання:

#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.