Implementa Sleep Sort


74

Sleep Sort è un algoritmo di ordinamento di numeri interi che ho trovato su Internet. Apre un flusso di output e, per ogni numero di input in parallelo, ritarda per il numero di secondi ed emette quel numero. A causa dei ritardi, l'ultimo numero verrà emesso per ultimo. Stimo che ha O (n + m), dove n è il numero di elementi e m è il numero più alto.

Ecco il codice originale in Bash

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

Ecco lo pseudocodice

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

Il tuo compito è implementare l'ordinamento in sospensione come funzione nel linguaggio di programmazione che preferisci. Puoi trascurare qualsiasi fattore di concorrenza come le condizioni di gara e non bloccare mai alcuna risorsa condivisa. Vince il codice più corto. La definizione della funzione conta per la lunghezza del codice.

L'elenco di input è limitato a numeri interi non negativi e la lunghezza dell'elenco di input dovrebbe essere ragionevolmente lunga (testare almeno 10 numeri) in modo che le condizioni di gara non si verifichino mai. e supponendo che le condizioni di gara non accadano mai.


3
Cosa conta per la lunghezza? Programmi completi incluso IO o solo la routine pertinente?
Konrad Rudolph,

8
Un problema con questo. A seconda dell'ordine della lista, potresti non leggere l'intera lista prima che il primo valore venga stampato. Ad esempio, un ampio elenco che richiede 45 secondi per la lettura, il primo valore è 2 e l'ultimo valore è 1. Il thread per stampare 1 potrebbe essere eseguito dopo la stampa di 2. Spiacenti, l'output non è più ordinato correttamente. Potrebbero esserci alcune soluzioni alternative: creare i thread e quindi avviarli dopo aver letto l'intero elenco (ma ciò porterà a un codice più lungo, contro il golf). Mi chiedo se qualcuno può fornire un golf che risolve questo potenziale problema ... Ci proverò.
Thomas Owens,

11
Per inciso, ciò che rende questo algoritmo davvero interessante è che in realtà esistono applicazioni nella vita reale. Ad esempio, il sequenziamento del DNA (Sanger sequenziamento) dipende da qualcosa del genere per ordinare i frammenti di DNA in base alla loro lunghezza (e più in generale, ogni elettroforesi fa qualcosa di simile). La differenza è che il sequenziamento viene eseguito fisicamente, non in un computer.
Konrad Rudolph,

12
Odio essere quello che piove sulla parata di tutti, ma questo non scarica la complessità sullo scheduler del sistema operativo in un modo che probabilmente è O (N ^ 2)?
Casuale 832

1
Penso che ci siano algoritmi di ordinamento fisico che richiedono O (n) tempo ma O (n) oggetti fisici. Bene, possiamo usare candele fondenti e un tubo per farlo. en.wikipedia.org/wiki/Spaghetti_sort
Ming-Tang,

Risposte:


17

Una specie di zoppo Perl , 59 55 52 38 32 caratteri :

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

Barebones: 25 Personaggi:

... se non ti dispiace i risultati dell'ordinamento come output die:

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

Con tutte le guarnizioni:

(per la massima conformità alla sfida, 44 caratteri)

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

Se permetti a perl di aspettarti, 39 caratteri:

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

E ancora, se non ti dispiace die(), 32 personaggi ...

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

Si noti che in Perl 6, o quando viene dichiarata la funzione 'say', è possibile sostituire la printfunzione con say, salvando un carattere in ogni istanza. Ovviamente poiché dieentrambi terminano il processo a fork e scrivono l'output, rimane la soluzione più breve.


puoi eseguire la corsa perl-Eper abilitare le funzionalità di 5.010 comesay
mbx

(fork&&die sleep$_)for@afunziona anche
Malkaroee,

20

C , 127 caratteri, una soluzione piuttosto ovvia:

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

(Compilato gcc -std=c99 -fopenmp sort.ce ignorato tutti gli avvisi.)


4
Fantastico, devo davvero imparare Opemp
Nils,

Lo chiamerei 93 caratteri (senza analisi della riga di comando e simili), ma è impressionante che tu possa farlo in soli 34 caratteri extra in C!
Rex Kerr,

1
@KonradRudolph - È possibile salvare 6 bytes che vanno indietro: for(;c>=0;--c){int x=atoi(v[c]);. Non sono sicuro che sia permesso.
owacoder,

15

Ruby 1.9, 32 caratteri

Come una funzione:

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

Se possiamo semplicemente usare una variabile predefinita, si riduce a 25 caratteri:

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

1
È possibile salvare alcuni caratteri utilizzando Thread.new{p sleep i}per stampare l'output.
Howard,

@Howard: buona cattura, grazie!
Ventero,

@Ventero, sto solo imparando Ruby e mi piacerebbe sapere come eseguiresti questa funzione lambda o più specificamente come darai un contributo. È possibile eseguire con IRB? Grazie!
Ben Hili,

14

JavaScript , 65 caratteri (a seconda che tu usi console.logo qualcos'altro per produrre il risultato)

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

Ciò presuppone che si atratti di un array di numeri interi non negativi e che map()esiste sul prototipo di array (JavaScript 1.6+).


1
Probabilmente puoi radere due o anche tre caratteri moltiplicando per 10 (o 9) invece di 1000, senza compromettere la correttezza.
Konrad Rudolph,

12
Se si desidera che un secondo rimanga, è possibile utilizzare 1e3invece.
Joey,

2
@Tomalak, alertè l'output di blocco di JavaScript, promptè l'input di blocco di JavaScript ed confirmè l'input binario di blocco di JavaScript. Se JS dovesse essere scritto sulla riga di comando, quelle sarebbero le chiamate che useresti.
zzzzBov,

1
@zzzzBov, l'utilizzo dell'output di blocco sarebbe quasi sicuramente una cattiva idea per questo compito.
Peter Taylor,

2
@zzzzBov, è l'ordine in cui vengono chiamati di cui sono preoccupato - a meno che le specifiche JS non abbiano forti garanzie sull'ordine in cui vengono chiamati i thunks accodati da setTimeout.
Peter Taylor,

13

APL ( 15 13)

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

Cosa fa:

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

Vedo caselle invece di 3 caratteri.
defhlt

8
@ArtemIce: dovrebbero esserci tre scatole (quadretti). Due sono la variabile I / O (leggendo ottiene input e scrivendo su di essa stampa output), e uno è nel nome della ⎕DLfunzione che è sleep.
Marin

9

Quattro tentativi a Erlang:

Uscita sulla console, si sono presi la libertà di farlo ciascuno 9ms * Numberpoiché questo è abbastanza per farlo funzionare (testato su una scheda Atom integrata = lenta):

Ha bisogno di 60 caratteri

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

L'output sulla console è totalmente non-cancellabile, quindi inviamo un messaggio da elaborare Pinvece:

Ha bisogno di 55 caratteri

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

Anche l'invio dopo un certo periodo di tempo può essere effettuato in modo diverso (funziona anche con 1ms * Number):

Ha bisogno di 41 caratteri

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

In realtà questo è un po 'ingiusto poiché la funzione integrata send_afterè in ritardo e necessita dello spazio dei nomi con erlang:prefisso, se consideriamo questo spazio dei nomi importato (fatto a livello di modulo):

Ha bisogno di 34 caratteri

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

7

C # - 137 caratteri

Ecco una risposta in C # (aggiornata con gradi di parallelismo come commentato)

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

1
Dovrai specificare WithDegreeOfParallelismche funzioni, analogamente al num_threadsmio codice OpenMP C.
Konrad Rudolph,

120 byte:void m(int[] l){foreach(var i in l){var t=new Thread(()=>{Thread.Sleep(int.Parse(s));Console.Write(s);});t.Start();}}}
Paul Paul

@MrPaulch Nota che devi unirti di nuovo ai thread, se vuoi che il tuo programma abbia il comportamento previsto
Yet Another Geek

Perché? Il thread in esecuzione più lungo manterrà vivo il processo.
Mr Paul Paul

7

Python - 81 93 148 150 153

Modifica del codice di BiggAl, dato che è il gioco a cui stiamo giocando ...

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

... o 97 175 con avviamento ritardato del filo

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

Accetta input dalla riga di comando, ala

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

Come con molti golf python, arriva un punto in cui il codice è abbastanza compatto che l'aliasing delle variabili per abbreviare i nomi non salva nemmeno i caratteri.

Questo è funky però perché alias sys e thread ENTRAMBE come t, quindi sys.argv diventa t.argv. Più breve rispetto all'importazione di foo * e un risparmio netto di carattere! Comunque suppongo che Guido non sarebbe contento ...

Nota per l'autoapprendimento ce smettere di giocare a golf in Python. SANTA MUCCA QUESTO È PIÙ BREVE DELLA SOLUZIONE C!


Sono riuscito a fare alcune modifiche, ma la formattazione non viene visualizzata bene nei commenti, quindi ho creato la mia risposta. daemonnon ha bisogno di essere settato a meno che tu non lo stia avviando come demone, ed è più breve usare arg posizionali, esp. se alias NoneaN
theheadofabroom

Oh, e il primo non funziona per me al punto 2.7.1, come jsembra finire come False- un effetto collaterale del tentativo di fare troppo in una riga?
theheadofabroom il

merda, non mi ero reso conto che potresti importare più moduli nello stesso alias - potrei davvero pensare ad alcuni usi per quello in cui ho più sottoclassi della stessa classe base personalizzata che giacciono in sotto-moduli separati. Se riusciamo a radere altri 30 è più corto di bash ... Ma non penso che succederà.
theheadofabroom

Argh il motivo per cui non lo sapevo è perché non puoi - ho appena provato a eseguirlo e il threading non è alias, si chiama semplicemente threading. È il sistema che è alias to ... Hai provato a farlo? Tuttavia, sono solo 2 caratteri aggiuntivi per ciascuno da importare as t,se poi utilizzare spersys
theheadofabroom

1
perché non usi la printfunzione invece di sys.stdout.write?
pecora volante

6

Per divertimento, ecco una versione di ColdFusion (8+) ;-) Ha 109 caratteri che non contano gli avvolgimenti di riga e il rientro che ho aggiunto per leggibilità qui.

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

Questo presuppone che <cfoutput>sia in vigore. Alcuni personaggi potrebbero essere salvati scrivendo tutto su una riga.


6

Java (alias mai vince a codegolf): 234 211 187 caratteri

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

@Joey grazie per averlo chiarito.
verità

La classe può essere non pubblica, risparmiando 7 caratteri.
Daniel Lubarov,

1
Puoi anche dichiarare throws Throwablee sbarazzarti della catchclausola.
Daniel Lubarov,

Penso che puoi salvare 2 byte sostituendoli Long.parseLongcon Long.valueOf.
HyperNeutrino,

So che sono passati 6,5 anni, ma puoi giocare a golf alcune parti: publice finalpossono essere rimosse; class M{public static void mainpuò essere interface M{static void main(Java 8+); Long.parseLong(a)può essere new Long(a)(risultante in 165 byte )
Kevin Cruijssen,

5

Javascript - 52 caratteri

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

Benvenuto in CodeGolf.SE! Ho formattato la tua risposta per te, in particolare indentando il tuo codice di quattro spazi per farlo visualizzare come codice. Troverai altri aiuti per la formattazione nella barra laterale della pagina di modifica.
dmckee,

5

Scala - 42 40 caratteri (custodia speciale)

Se si dispone di un pool di thread almeno delle dimensioni del numero di elementi dell'elenco:

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

Scala - 72 caratteri (generale)

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

afaik non usi {}quando stai su una linea.
pecora volante

@flying sheep - Puoi omettere {}con una frase , ma ti serve ancora per raggruppare le cose separate da ;, una riga o no. E puoi scrivere istruzioni multilinea senza {}in alcuni casi (if / else per esempio).
Rex Kerr,

oh, non volevo dire che puoi ometterli, ma che puoi usare invece ()per le linee singole. è una questione di gusti lì, penso. (Semplicemente non capisco perché ()sono supportati affatto quando {}li sostituiscono. Forse per non alienare istantaneamente gli utenti Java). Scala è interessante, ma definire blocchi di codice per rientro è chiaramente superiore. (e così, la guerra religiosa ne consegue;))
volare pecore il

Pecora @flying - Sei male informato. È possibile utilizzare ()per singole dichiarazioni. Prova ad entrare (1 to 9).map(i => {val j = i+1; i*j})nel REPL e poi vedi cosa succede se lo usi (1 to 9).map(i => (val j = i+1; i*j)).
Rex Kerr,

vero, ma mi riferivo solo a espressioni e cose. Mi dispiace, odio scrivere cose senza poter usare le interruzioni di riga;)
volare pecore il

4

Haskell - 143 caratteri

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

Questo probabilmente potrebbe essere abbreviato prendendo input su stdin se fosse un'opzione, ma è tardi e in entrambi i casi, è ancora 104 caratteri per la funzione stessa.


4

Befunge-98, 38 31 byte

So che questa è una vecchia sfida, ma di recente ho scoperto sia i linguaggi sleepsort che i linguaggi 2D, ho avuto un'idea su come combinarli e ho cercato un posto per pubblicarlo, quindi eccoci qui.

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

L'IP principale legge un numero ( &), quindi colpisce chi lo tclona: uno procede sulla stessa linea e cicli, leggendo nuovi numeri e generando nuovi figli fino a raggiungere EOF che termina la sequenza. Tutti i processi figlio rimangono bloccati in un ciclo chiuso (la ve ^della terza colonna) fino a quando l'IP principale non termina la lettura dell'input ed esegue la sequenza di comandi '<21p, che mette il carattere <in posizione (1,2), sovrascrivendo ^e liberando tutto i processi figlio, che iniziano a scorrere contemporaneamente, riducendo di 1 il loro numero ad ogni iterazione. Poiché la velocità di esecuzione di IP diversi è sincronizzata in befunge, termineranno (e stamperanno il loro valore) in ordine, ordinando l'elenco di input.


26 byte spostando un po 'il flusso di controllo.
Jo King,

3

Un po 'in ritardo alla festa:

Acero - 91 83 caratteri

Nel 91:

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

Nell'83:

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

(Ciò richiede Maple versione 15 e si aspetta che l'elenco venga ordinato in L)


3

C, 70 69 caratteri

Non attende la restituzione dei processi figlio, altrimenti funziona.

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

2

PHP 57 byte

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

pcntl_fork () è disponibile solo su Linux.


2

Bash (38):

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

Modifica: virgola mobile dallo stdin, separato da spazi o newline.


2

Haskell, 90

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

Spero che questo soddisfi tutti i requisiti.



1

Solo alcune modifiche dalla versione di @rmckenzie:

Inizio del thread ritardato 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 senza indugio 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()

Ha gestito alcune ulteriori ottimizzazioni, utilizzando Timerinvece di Thread, che ha una chiamata più concisa e ha rimosso la necessità di importare time. Il metodo di avvio ritardato del thread trae vantaggio dalla comprensione dell'elenco in quanto elimina la necessità di inizializzare l'elenco separatamente all'inizio, sebbene sia più lungo di due caratteri ( "["+"]"+" "-":") rispetto al ciclo for, quindi è inutile senza avvio ritardato e devi fare attenzione a usare un elenco piuttosto che un generatore, o in realtà non stai creando i thread del timer fino a quando non attraversi il generatore.

Qualcun altro ha qualche ottimizzazione?


Il trucco con asaiuta, ma in 2.7.1 puoi importare solo un modulo in un alias, e dopo aver giocato un po 'su di te non puoi nemmeno import mod1,mod2 as a,b, devi farlo import mod1 as a, mod2 as b. Salva ancora alcuni personaggi, ma non è proprio la cura-tutto ciò che pensavo fosse ... E in effetti è meglio lasciare sys come sys. Aliasing threading aiuta ancora comunque ...


mi hai fatto battere, avere un aggiornamento. Mi piace x = []; x + = []. Non sapevo che potevi farlo ...
Arrdem,

... potresti farlo nel 128 se perdi gli spazi tra: [istruzione] nel tuo ciclo ef (x) ... in qualche modo l'ho portato a 127, ma penso che non contando la nuova riga finale (che è legittimo in CG). Ho pensato di darti l'aggiornamento piuttosto che essere uno strumento e rubare il tuo codice.
Arrdem,

@rmckenzie provaci, ho rubato il tuo. Sono sempre interessato a vedere il pitone CG - mi sento come se stessi facendo qualcosa di molto perverso considerando gli obiettivi del linguaggio ...
theheadofabroom

Sì, sono sinceramente scioccato da quanto siano leggibili la maggior parte dei golf in pitone ... al costo di un "pavimento di vetro" di personaggi.
Dai un'occhiata a

1

Clojure, 54

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


puoi sbarazzarti di alcuni caratteri incorporando l'omissione defn(parentesi + elenco di argomenti: da 54 a 43 chrs), oppure usa fninvece di defn=> len- = 2, quindi direi in clj il suo 43: D
test30

1

Ruggine - 150 byte

Ed è per questo che non si codice golf in Rust, è più prolisso di Java;). Dipende dalla cassa esterna crossbeam, senza di essa sarebbe anche peggio.

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

Programma di test completo:

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

Tipo di noioso, porto di C #, solo per ricominciare con la lingua:

F # - 90 caratteri

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

o 71/65 caratteri con non standardità:

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

Anche nel 2011 penso che function(a){a.map(function(v){setTimeout(console.log,v,v)})}potrebbe aver funzionato in almeno un browser per 60 byte. Ovviamente in questi giorni a=>a.map(v=>setTimeout(console.log,v,v))invece scriveresti .
Neil

0

Tcl 8.6, 41 caratteri

lmap c $argv {after $c "puts $c"};vwait f

Devi ucciderlo con ^C


0

VB.NET 100 byte

Poiché VB.Net richiede lambda a riga singola per contenere solo un'istruzione, questo codice deve contenere più righe:

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

Tuttavia non sono sicuro se conti le dichiarazioni di importazione nei conteggi dei byte perché se non le conti allora potrei scrivere questo:

VB.NET 71 byte

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 byte

Presuppone che i numeri siano indicati nella riga di comando ...

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


0

Mathematica, 34 o 36 byte

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

Basta aggiungere l'elenco da ordinare alla fine di questo codice e valutare. Se deve essere una definizione di funzione valida, sono necessari due byte extra:

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

0

C ++ 11, 229 byte

#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 e utilizzo:

#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;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.