Implementar Sueño Ordenar

74

Sleep Sort es un algoritmo de clasificación de enteros que encontré en Internet. Abre una secuencia de salida y, para cada número de entrada en paralelo, demora los segundos y emite ese número. Debido a los retrasos, el número más alto se emitirá en último lugar. Estimo que tiene O (n + m), donde n es el número de elementos ym es el número más alto.

Aquí está el código original en Bash

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

Aquí está el pseudocódigo

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

Su tarea es implementar Sleep Sort como una función en el lenguaje de programación que elija. Puede descuidar cualquier factor de concurrencia, como las condiciones de la carrera, y nunca bloquear los recursos compartidos. El código más corto gana. La definición de la función cuenta para la longitud del código.

La lista de entrada se limita solo a enteros no negativos, y se espera que la longitud de la lista de entrada sea razonablemente larga (pruebe al menos 10 números) para que las condiciones de carrera nunca ocurran. y suponiendo que las condiciones de carrera nunca sucedan.

Ming-Tang
fuente
3
¿Qué cuenta para la longitud? ¿Programas completos que incluyen IO o solo la rutina relevante?
Konrad Rudolph
8
Un problema con esto. Según el orden de la lista, es posible que no lea toda la lista antes de que se imprima el primer valor. Por ejemplo, una lista grande que tarda 45 segundos en leerse, el primer valor es 2 y el último valor es 1. El hilo para imprimir 1 podría ejecutarse después de que se imprima el 2. ¡Vaya! La salida ya no se ordena correctamente. Puede haber algunas soluciones: crear los hilos y luego comenzarlos después de leer toda la lista (pero eso conducirá a un código más largo, en contra del golf). Me pregunto si alguien puede proporcionar un campo de golf que aborde este problema potencial ... Voy a intentarlo.
Thomas Owens
11
Por cierto, lo que hace que este algoritmo sea realmente interesante es que en realidad existen aplicaciones de la vida real. Por ejemplo, la secuenciación de ADN (secuenciación de Sanger) depende de algo como esto para clasificar los fragmentos de ADN de acuerdo con su longitud (y, en general, cada electroforesis hace algo similar). La diferencia es que la secuenciación se realiza físicamente, no en una computadora.
Konrad Rudolph
12
Odio ser el que llueva en el desfile de todos, pero ¿esto no solo descarga la complejidad en el programador del sistema operativo de una manera que probablemente sea O (N ^ 2)?
Random832
1
Creo que hay algoritmos de clasificación física que requieren tiempo O (n) pero objetos físicos O (n). Bueno, podemos usar velas derretidas y un tubo para hacerlo. en.wikipedia.org/wiki/Spaghetti_sort
Ming-Tang

Respuestas:

17

Una especie de cojo intento de Perl , 59 55 52 38 32 caracteres :

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

Barebones: 25 Personajes:

... si no le importan los resultados de clasificación como salida de matriz:

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

Con todos los adornos:

(para cumplimiento de desafío máximo, 44 caracteres)

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

Si dejas que Perl te espere, 39 caracteres:

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

Y de nuevo, si no te importa die(), 32 caracteres ...

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

Tenga en cuenta que en Perl 6, o cuando se declara la función 'decir', es posible reemplazar la printfunción con say, guardando un carácter en cada instancia. Obviamente, dado que dieambos finalizan el proceso bifurcado y escriben la salida, sigue siendo la solución más corta.

Christopher
fuente
todavía puede ejecutar perl-Epara habilitar características 5.010 comosay
mbx
(fork&&die sleep$_)for@afunciona también
malkaroee
20

C , 127 caracteres, una solución bastante obvia:

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

(Compilado gcc -std=c99 -fopenmp sort.ce ignorando todas las advertencias).

Konrad Rudolph
fuente
44
Genial, realmente tengo que aprender opemp
Nils
Yo llamaría a eso 93 caracteres (sin análisis de línea de comandos y demás), ¡pero es impresionante que puedas hacerlo en solo 34 caracteres adicionales en C!
Rex Kerr
1
@KonradRudolph - Puede guardar 6 bytes que van hacia atrás: for(;c>=0;--c){int x=atoi(v[c]);. No estoy seguro si eso está permitido.
owacoder
15

Ruby 1.9, 32 caracteres

Como una función:

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

Si solo podemos usar una variable predefinida, se reduce a 25 caracteres:

a.map{|i|fork{p sleep i}}
Ventero
fuente
1
Puede guardar bastantes caracteres utilizando Thread.new{p sleep i}para imprimir la salida.
Howard
@Howard: Buena captura, gracias!
Ventero
@Ventero, solo estoy aprendiendo Ruby y me gustaría saber cómo ejecutarías esta función lambda o, más específicamente, cómo le darías una entrada. ¿Es posible correr con IRB? ¡Gracias!
Ben Hili
14

JavaScript , 65 caracteres (dependiendo de si usa console.logu otra cosa para generar el resultado)

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

Esto supone que aes una matriz de enteros no negativos y que map()existe en el prototipo de matriz (JavaScript 1.6+).

Tomalak
fuente
1
Probablemente pueda eliminar dos o incluso tres caracteres al multiplicar por 10 (o 9) en lugar de 1000, sin comprometer la corrección.
Konrad Rudolph
12
Si el segundo está destinado a permanecer, probablemente pueda usarlo 1e3en su lugar.
Joey
2
@Tomalak, alertes la salida de bloqueo de JavaScript, promptes la entrada de bloqueo de JavaScript y confirmes la entrada binaria de bloqueo de JavaScript. Si JS se escribiera en la línea de comando, esas serían las llamadas que usaría.
zzzzBov
1
@zzzzBov, el uso de la salida de bloqueo seguramente sería una mala idea para esta tarea.
Peter Taylor
2
@zzzzBov, es el orden en que se llaman lo que me preocupa, a menos que la especificación JS tenga fuertes garantías sobre el orden en que se llaman los thunks en cola setTimeout.
Peter Taylor
13

APL ( 15 13)

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

Que hace:

¨⎕       : for each element of the input
&        : do on a separate thread
⎕DL⍵    : wait approx. ⍵ seconds
⎕←⍵     : output ⍵
marinus
fuente
Veo cuadros en lugar de 3 caracteres.
defhlt
8
@ArtemIce: Se supone que hay tres cuadros (quads). Dos son la variable de E / S (leerla recibe entrada y escribir en ella imprime salida), y una está en el nombre de la ⎕DLfunción que es dormir.
marinus
9

Cuatro intentos en Erlang:

Salida a la consola, se han tomado la libertad de hacer esto cada 9ms * Numbervez que esto es suficiente para que funcione (probado en una placa integrada Atom = lenta):

Necesita 60 caracteres

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

La salida a la consola es total sin Erlangish, por lo que enviamos un mensaje para procesar en su Plugar:

Necesita 55 caracteres

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

El envío después de un tiempo también se puede hacer de manera diferente (esto incluso funciona con 1ms * Number):

Necesita 41 caracteres

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

En realidad, esto es un poco injusto ya que la función incorporada send_afteres un retraso y necesita el espacio de nombre con erlang:prefijo, si consideramos que este espacio de nombre es importado (hecho a nivel de módulo):

Necesita 34 caracteres

s(P,L)->[send_after(X,P,X)||X<-L].
Peer Stritzinger
fuente
7

C # - 137 caracteres

Aquí hay una respuesta en C # (actualizada con grados de paralelismo como se comentó)

void ss(int[]xs){xs.AsParallel().WithDegreeOfParallelism(xs.Length).Select(x=>{Thread.Sleep(x);return x;}).ForAll(Console.WriteLine);}
Otro geek
fuente
1
Tendrá que especificar WithDegreeOfParallelismpara que esto funcione, de manera análoga al num_threadscódigo C de OpenMP.
Konrad Rudolph
120 bytes: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 Tenga en cuenta que necesita unirse a los hilos nuevamente, si desea que su programa tenga el comportamiento esperado
Sin embargo, otro friki
¿Por qué? El hilo de ejecución más largo mantendrá vivo el proceso.
MrPaulch
7

Python - 81 93 148 150 153

Ajustando el código de @ BiggAl, ya que ese es el juego que estamos jugando ...

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

... o 97 175 con inicio retrasado del hilo

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

Toma entrada a través de la línea de comando, ala

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

Al igual que con muchos campos de golf de Python, llega un punto en el que el código es lo suficientemente compacto como para que las variables de alias para acortar los nombres ni siquiera guarden caracteres.

Sin embargo, este es funky porque alias sys y enhebrar AMBOS como t, por lo que sys.argv se convierte en t.argv. Más corto que el de foo import *, ¡y un ahorro neto de caracteres! Sin embargo, supongo que a Guido no le agradaría ...

Nota para el autoaprendizaje c y dejar de jugar golf en python. ¡VACA SANTA ESTO ES MÁS PEQUEÑO QUE LA SOLUCIÓN C!

arrdem
fuente
Logré hacer algunos ajustes, pero el formato no se ve bien en los comentarios, así que hice mi propia respuesta. daemonno necesita configuración a menos que esté comenzando esto como un demonio, y es más corto usar argumentos posicionales, esp. si alias NoneaN
theheadofabroom
Ah, y el primero no funciona para mí en 2.7.1, como jparece terminar siendo Falseun efecto secundario de tratar de hacer demasiado en una línea.
theheadofabroom
Mierda, no me di cuenta de que podía importar varios módulos al mismo alias. De hecho, podría pensar en algunos usos para los que tengo varias subclases de la misma clase base personalizada en submódulos separados. Si podemos eliminar otros 30, es más corto que bash ... Pero no creo que eso suceda.
theheadofabroom
Argh, la razón por la que no lo sabía es porque no puedes: solo intenté ejecutarlo y el subproceso no tiene alias, solo se llama subprocesamiento. Es el sistema alias t ... ¿Intentaste ejecutar esto? Es sólo un extra de 2 caracteres en cada aunque para importar as t,sy luego cambiar a utilizar sparasys
theheadofabroom
1
¿Por qué no usas la printfunción en lugar de sys.stdout.write?
ovejas voladoras
6

Por diversión, aquí hay una versión de ColdFusion (8+) ;-) Tiene 109 caracteres sin contar los ajustes de línea y la sangría que agregué para legibilidad aquí.

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

Esto supone que <cfoutput>está vigente. Se pueden guardar algunos caracteres escribiéndolo todo en una línea.

Tomalak
fuente
6

Java (alias nunca gana en codegolf): 234 211 187 caracteres

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

sin golf:

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();
    }
}
la verdad
fuente
@ Joey, gracias por aclararlo.
trutheality
La clase puede ser no pública, ahorrando 7 caracteres.
Daniel Lubarov
1
También puede declarar throws Throwabley deshacerse de la catchcláusula.
Daniel Lubarov
Creo que puede guardar 2 bytes reemplazando Long.parseLongcon Long.valueOf.
HyperNeutrino
Sé que han pasado 6.5 años, pero puedes jugar al golf en algunas partes: publicy finalpuedes quitarlo; class M{public static void mainpuede ser interface M{static void main(Java 8+); Long.parseLong(a)puede ser new Long(a)(resultando en 165 bytes )
Kevin Cruijssen
5

Javascript - 52 caracteres

for(i in a)setTimeout("console.log("+a[i]+")",a[i])
Arkind
fuente
Bienvenido a CodeGolf.SE! He formateado su respuesta para usted, en particular sangrando su código por cuatro espacios para que se muestre como código. Encontrará otra ayuda de formato en la barra lateral de la página de edición.
dmckee
5

Scala - 42 40 caracteres (caso especial)

Si tiene un grupo de subprocesos de al menos el tamaño del número de elementos de la lista:

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

Scala - 72 caracteres (general)

a.map(i=>new Thread{override def run{Thread.sleep(i);println(i)}}.start)
Rex Kerr
fuente
afaik que no usas {}cuando te quedas en una línea.
ovejas voladoras
@ ovejas voladoras: puede omitir {}con una declaración , pero aún la necesita para agrupar las cosas separadas por ;una línea o no. Y puede escribir enunciados de varias líneas sin {}en algunos casos (si / si no, por ejemplo).
Rex Kerr
oh, no quise decir que puedes omitirlos, sino que puedes usarlos ()para una línea. Es una cuestión de gustos, creo. (Realmente no entiendo por qué ()son compatibles cuando los {}reemplazo. Tal vez para no alienar a los usuarios de Java al instante). Scala es genial, pero definir bloques de código por sangría es claramente superior. (y así, sobreviene la guerra religiosa;))
ovejas voladoras
@ ovejas voladoras - Estás mal informado. Puede usar ()para declaraciones individuales. Intente ingresar (1 to 9).map(i => {val j = i+1; i*j})en REPL y luego vea qué sucede si lo usa (1 to 9).map(i => (val j = i+1; i*j)).
Rex Kerr
cierto, pero solo me referí a las expresiones y esas cosas. Lo siento, odio escribir cosas sin poder usar saltos de línea;)
ovejas voladoras
4

Haskell - 143 caracteres

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

Esto probablemente podría acortarse si se ingresa en stdin si esa fuera una opción, pero es tarde y de cualquier manera, todavía son 104 caracteres para la función en sí.


fuente
4

Befunge-98, 38 31 bytes

Sé que este es un viejo desafío, pero recientemente descubrí los lenguajes Sleepsort y 2D, tuve una idea sobre cómo combinarlos y busqué un lugar para publicarlo, así que aquí estamos.

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

La IP principal lee un número ( &), luego toca el tque lo clona: uno avanza en la misma línea y realiza ciclos, leyendo nuevos números y generando nuevos hijos hasta que alcanza EOF que termina la secuencia. Todos los procesos secundarios se atascan en un bucle cerrado (el vy ^de la tercera columna) hasta que la IP principal termina de leer la entrada y ejecuta la secuencia de comandos '<21p, lo que coloca el carácter <en la posición (1,2), sobrescribiendo ^y liberando todo los procesos secundarios, que comienzan a alternar simultáneamente, reduciendo en 1 su número en cada iteración. Como la velocidad de ejecución de diferentes IP se sincroniza en befunge, terminarán (e imprimirán su valor) en orden, ordenando la lista de entrada.

León
fuente
26 bytes moviendo el flujo de control un poco.
Jo King el
3

Un poco tarde para la fiesta:

Arce - 91 83 caracteres

En 91:

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

En 83:

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

(Esto necesita Maple versión 15, y espera que la lista se ordene en L)

John M
fuente
3

C, 70 69 caracteres

No espera a que vuelvan los procesos secundarios, de lo contrario funciona.

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

PHP 57 bytes

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

pcntl_fork () solo está disponible en Linux.

primo
fuente
2

Golpe (38):

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

Editar: coma flotante desde stdin, separados por espacios o nuevas líneas.

yingted
fuente
2

Haskell, 90

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

Espero que esto cumpla con todos los requisitos.

shiona
fuente
1

Solo algunos ajustes de la versión de @rmckenzie:

Python retrasó el inicio del hilo en 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 sin demora en 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()

Gestioné algunas optimizaciones más, utilizando en Timerlugar de Thread, que tiene una llamada más concisa y eliminó la necesidad de importar time. El método de inicio de subproceso retrasado se beneficia de la comprensión de la lista, ya que elimina la necesidad de inicializar la lista por separado al inicio, aunque son dos caracteres más largos ( "["+"]"+" "-":") que el bucle for, por lo que es inútil sin inicio diferido, y debe tener cuidado de usar una lista en lugar de un generador, o en realidad no estás creando los hilos del temporizador hasta que atravieses el generador.

¿Alguien más tiene alguna optimización?


El truco con asayuda, pero en 2.7.1 solo puedes importar un módulo en un alias, y después de jugar un poco sobre eso, ni siquiera import mod1,mod2 as a,btienes que hacerlo import mod1 as a, mod2 as b. Todavía guarda algunos caracteres, pero no es la cura, todo lo que pensé que era ... Y, de hecho, es mejor dejar sys como sys. Sin embargo, el enhebrado de alias todavía ayuda ...

theheadofabroom
fuente
me tienes vencido, tienes un ascenso. Me gusta la x = []; x + = []. No sabía que se podía hacer eso ....
arrdem
... podría hacer esto en 128 si pierde los espacios entre: [instrucción] en su bucle yf (x) ... de alguna manera llegué a 127, pero creo que eso es sin contar la nueva línea final (que es legítimo en CG). Pensé en darte la actualización en lugar de ser una herramienta y robar tu código.
Arrdem
@rmckenzie, adelante, robé el tuyo. Siempre estoy interesado en ver Python CG - Siento que estoy haciendo algo muy perverso teniendo en cuenta los objetivos del lenguaje ...
theheadofabroom
Sí, estoy sinceramente sorprendido por la legibilidad de la mayoría de los campos de golf de pitón ... a costa de un "piso de cristal" de personajes. Mira esto: importación de subprocesos, sys como t
arrdem
1

Clojure, 54

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

defhlt
fuente
puede deshacerse de algunos caracteres al omitir en línea defn(sus corchetes + lista de argumentos: de 54 a 43 caracteres), o usar en fnlugar de defn=> len- = 2, así que diría en clj su 43: D
test30
1

Óxido - 150 bytes

Y es por eso que no codificas golf en Rust, es más detallado que Java;). Depende de la caja externa crossbeam, sería aún peor sin ella.

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

Programa de prueba 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])
}
Konrad Borowski
fuente
0

Tipo de aburrido, puerto de C #, solo para comenzar con el lenguaje nuevamente:

F # - 90 caracteres

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

JavaScript, 74

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

o 71/65 caracteres con no estándar:

function(a){a.map(function(v){setTimeout('console.log('+v+')',v*1e3)})}
Ry-
fuente
Incluso en 2011, creo que function(a){a.map(function(v){setTimeout(console.log,v,v)})}puede haber funcionado en al menos un navegador durante 60 bytes. Por supuesto, en estos días escribirías en su a=>a.map(v=>setTimeout(console.log,v,v))lugar.
Neil
0

Tcl 8.6, 41 caracteres

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

Tienes que matarlo con ^C

Johannes Kuhn
fuente
0

VB.NET 100 bytes

Debido a que VB.Net requiere lambdas de una sola línea para contener solo una instrucción, este código debe tener varias líneas:

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

Sin golf:

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

Sin embargo, no estoy seguro si cuenta las declaraciones de importación en el recuento de bytes porque si no las cuenta, podría escribir esto:

VB.NET 71 bytes

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

Sin golf:

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
вʀaᴎᴅᴏƞ вєнᴎєƞ
fuente
0

Groovy, 47 bytes

Asume que los números se dan en la línea de comando ...

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

K. Klassen
fuente
0

Mathematica, 34 o 36 bytes

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

Simplemente agregue la lista que se ordenará al final de este código y evalúe. Si necesita ser una definición de función válida, entonces toma dos bytes adicionales:

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

C ++ 11, 229 bytes

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

Sin golf y uso:

#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;
}
Karl Napf
fuente