Implementar classificação de suspensão


74

Classificação do sono é um algoritmo de classificação inteira que eu encontrei na Internet. Ele abre um fluxo de saída e, para cada número de entrada em paralelo, atrasa o número segundos e gera esse número. Devido aos atrasos, o número mais alto será emitido por último. Estimo que tenha O (n + m), onde n é o número de elementos e m é o número mais alto.

Aqui está o código original no Bash

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

Aqui está o 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

Sua tarefa é implementar o Sleep Sort como uma função na linguagem de programação de sua escolha. Você pode negligenciar qualquer fator de simultaneidade, como condições de corrida, e nunca bloquear nenhum recurso compartilhado. O código mais curto vence. A definição da função conta para o comprimento do código.

A lista de entrada é limitada apenas a números inteiros não negativos, e o comprimento da lista de entrada deve ser razoavelmente longo (teste pelo menos 10 números) para que as condições da corrida nunca aconteçam. e assumindo que as condições da corrida nunca acontecem.


3
O que conta para o comprimento? Programas completos, incluindo IO ou apenas a rotina relevante?
Konrad Rudolph

8
Um problema com isso. Dependendo da ordem da lista, talvez você não leia a lista inteira antes que o primeiro valor seja impresso. Por exemplo, uma lista grande que leva 45 segundos para ler, o primeiro valor é 2 e o último valor é 1. O encadeamento para imprimir 1 pode ser executado depois que o 2 for impresso. Ops - a saída não está mais classificada corretamente. Pode haver algumas soluções alternativas - criar os encadeamentos e iniciá-los após a leitura de toda a lista (mas isso levará a um código mais longo, contra o golfe). Gostaria de saber se alguém pode fornecer um golfe que aborda esse problema em potencial ... eu vou tentar.
Thomas Owens

11
Aliás, o que torna esse algoritmo realmente interessante é que realmente existem aplicativos da vida real. Por exemplo, o seqüenciamento de DNA (sequenciamento de Sanger) depende de algo assim para classificar os fragmentos de DNA de acordo com seu comprimento (e geralmente, toda eletroforese faz algo semelhante). A diferença é que o seqüenciamento é realizado fisicamente, não em um computador.
Konrad Rudolph

12
Eu odeio ser o único a chover no desfile de todo mundo, mas isso não apenas transfere a complexidade para o agendador do SO de uma maneira que provavelmente é O (N ^ 2)?
usar o seguinte código

1
Eu acho que existem algoritmos de classificação física que levam O (n) tempo, mas O (n) objetos físicos. Bem, podemos usar velas derretidas e um tubo para fazer isso. en.wikipedia.org/wiki/Spaghetti_sort
Ming-Tang

Respostas:


17

Uma espécie de tentativa Perl esfarrapada , 59 55 52 38 32 caracteres :

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

Barebones: 25 Personagens:

... se você não se importa com os resultados da classificação como saída da matriz:

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

Com todas as guarnições:

(para máxima conformidade com os desafios, 44 caracteres)

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

Se você deixar o perl esperar por você, 39 caracteres:

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

E, novamente, se você não se importa die(), 32 caracteres ...

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

Observe que no Perl 6, ou quando o recurso 'say' é declarado, é possível substituir a printfunção por say, salvando um caractere em cada instância. Obviamente, como dieambos finalizam o processo bifurcado e gravam a saída, ela permanece a solução mais curta.


você pode stil executar perl-Epara habilitar 5.010 recursos comosay
MBX

(fork&&die sleep$_)for@afunciona também #
21336 malkaroee

20

C , 127 caracteres, uma solução bastante óbvia:

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 todos os avisos.)


4
Legal eu realmente tenho que aprender opemp
Nils

Eu chamaria isso de 93 caracteres (sem análise de linha de comando e outras), mas é impressionante que você possa fazer isso em apenas 34 caracteres extras em C!
Rex Kerr

1
@KonradRudolph - Você pode salvar 6 bytes indo para trás: for(;c>=0;--c){int x=atoi(v[c]);. Não tenho certeza se isso é permitido.
Owacoder 6/07

15

Ruby 1.9, 32 caracteres

Como uma função:

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

Se pudermos usar apenas uma variável predefinida, ela reduzirá para 25 caracteres:

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

1
Você pode salvar alguns caracteres usando Thread.new{p sleep i}para imprimir a saída.
Howard

@ Howard: Boa captura, obrigado!
Ventero

@ Ventero, estou apenas aprendendo Ruby e gostaria de saber como você executaria essa função lambda ou, mais especificamente, como você forneceria uma entrada. É possível executar com o IRB? Obrigado!
Ben Hili

14

JavaScript , 65 caracteres (dependendo se você usa console.logou outra coisa para gerar o resultado)

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

Isso pressupõe que aseja uma matriz de números inteiros não negativos e que map()exista no protótipo da matriz (JavaScript 1.6+).


1
Você provavelmente pode cortar dois ou até três caracteres multiplicando por 10 (ou 9) em vez de 1000, sem comprometer a correção.
Konrad Rudolph

12
Se o período de um segundo permanecer, você provavelmente poderá usá-lo 1e3.
Joey

2
@Tomalak, alerté a saída de bloqueio do JavaScript, prompté a entrada de bloqueio do JavaScript e confirmé a entrada binária de bloqueio do JavaScript. Se o JS fosse gravado na linha de comando, essas seriam as chamadas que você usaria.
precisa saber é o seguinte

1
@zzzzBov, usar o bloqueio de saída quase certamente seria uma má ideia para esta tarefa.
Peter Taylor

2
@zzzzBov, é a ordem na qual eles são chamados, com o qual estou preocupado - a menos que a especificação JS tenha fortes garantias sobre a ordem na qual os thunks em fila de espera do setTimeout são chamados.
Peter Taylor

13

APL ( 15 13)

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

O que faz:

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

Vejo caixas em vez de três caracteres.
defhlt

8
@ ArtItem: Deveria haver três caixas (quads). Duas são a variável de E / S (a leitura é recebida e a gravação é impressa), e uma é o nome da ⎕DLfunção que está em suspensão.
marinus

9

Quatro tentativas em Erlang:

Saída para o console, tiveram a liberdade de fazer isso cada um, 9ms * Numberpois isso é suficiente para fazê-lo funcionar (testado em uma placa incorporada Atom = lenta):

Precisa de 60 caracteres

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

A saída para o console é total não-Erlangish, por isso enviamos uma mensagem para processar P:

Necessita 55 caracteres

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

O envio após um tempo também pode ser feito de maneira diferente (isso funciona mesmo com 1ms * Number):

Necessita 41 caracteres

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

Na verdade, isso é um pouco injusto, pois a função incorporada send_afteré tardia e precisa do erlang:prefixo do namespace , se considerarmos esse namespace importado (feito no nível do módulo):

Necessita 34 caracteres

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

7

C # - 137 caracteres

Aqui está uma resposta em C # (atualizada com graus de paralelismo, como comentado)

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

1
Você precisará especificar WithDegreeOfParallelismpara que isso funcione, analogamente ao num_threadscódigo C do 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 Note que você precisa para se juntar os fios de novo, se você quiser que o seu programa para ter o comportamento esperado
Yet Another Geek

Por quê? O segmento de execução mais longo manterá o processo ativo.
MrPaulch

7

Python - 81 93 148 150 153

Ajustando o código do @ BiggAl, já que esse é o jogo que estamos jogando ....

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

... ou 97 175 com início de thread atrasado

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

Recebe entrada via linha de comando, ala

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

Como em muitos python golfs, chega um momento em que o código é compacto o suficiente para que as variáveis ​​de aliasing para encurtar nomes nem salvem caracteres.

Este aqui é descolado, porque alias sys e threading AMBOS como t, então sys.argv se torna t.argv. Menor que a importação de foo * e uma economia líquida de caracteres! No entanto, suponho que Guido não ficaria satisfeito ...

Nota para aprender sozinho c e parar de jogar golfe em python. VACA SANTA É MAIS CURTA DO QUE A SOLUÇÃO C!


Consegui fazer alguns ajustes, mas a formatação não aparece muito bem nos comentários, então fiz minha própria resposta. daemonnão precisa ser configurado, a menos que você esteja iniciando isso como um daemon e é mais curto usar argumentos posicionais, esp. se você alias NoneparaN
theheadofabroom 06/06

Ah, e o primeiro não funciona para mim no 2.7.1, como jparece acabar como False- um efeito colateral de tentar fazer muito em uma linha?
theheadofabroom 6/06/11

merda, eu não sabia que era possível importar vários módulos para o mesmo alias - na verdade, eu poderia pensar em alguns usos para isso, onde tenho várias subclasses da mesma classe base personalizada em sub-módulos separados. Se pudermos cortar outros 30, é mais curto que o bash ... Mas acho que não vai acontecer.
theheadofabroom

Argh, a razão pela qual eu não sabia é porque você não pode - eu apenas tentei executá-lo e o encadeamento não é um alias, é chamado de encadeamento. É sys que é alias para ... Você tentou executar isso? É apenas um extra de 2 caracteres em cada embora para importar as t,se, em seguida, mudar de usar sparasys
theheadofabroom

1
por que você não usa a printfunção em vez de sys.stdout.write?
ovelhas voadoras

6

Por diversão, aqui está uma versão do ColdFusion (8+) ;-) Ele possui 109 caracteres, sem contar as linhas e o recuo da linha que adicionei para legibilidade aqui.

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

Isso pressupõe que <cfoutput>está em vigor. Alguns caracteres podem ser salvos escrevendo tudo em uma linha.


6

Java (também conhecido como nunca vence no 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();}}

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 obrigado por esclarecer.
trutheality

A classe pode ser não pública, economizando 7 caracteres.
Daniel Lubarov

1
Você também pode declarar throws Throwablee se livrar da catchcláusula.
Daniel Lubarov 28/10

Eu acho que você pode salvar 2 bytes substituindo Long.parseLongpor Long.valueOf.
HyperNeutrino

Sei que já passaram 6,5 anos, mas você pode jogar golfe em algumas partes: publice finalpode ser removido; class M{public static void mainpode ser interface M{static void main(Java 8+); Long.parseLong(a)pode ser new Long(a)(resultando em 165 bytes )
Kevin Cruijssen

5

Javascript - 52 caracteres

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

Bem-vindo ao CodeGolf.SE! Formatei a resposta para você, recuando seu código em quatro espaços, para que ele seja exibido como código. Você encontrará outra ajuda de formatação na barra lateral da página de edição.
precisa

5

Scala - 42 40 caracteres (caso especial)

Se você tiver um conjunto de encadeamentos, pelo menos, o tamanho do número de elementos da lista:

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

Scala - 72 caracteres (geral)

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

você não usa {}quando fica em uma linha.
ovelhas voadoras

@ Voando ovelhas - Você pode omitir {}com uma declaração , mas ainda precisa agrupar as coisas separadas por ;, uma linha ou não. E você pode escrever instruções de várias linhas sem, {}em alguns casos (if / else por exemplo).
Rex Kerr

ah, não quis dizer que você pode omiti-los, mas que você pode usar apenas ()uma vez. é uma questão de gosto lá, eu acho. (Eu realmente não entendo por que eles ()são suportados quando os {}substituem. talvez para não alienar os usuários java instantaneamente). Scala é legal, mas definir blocos de código por indentação é claramente superior. (e assim, a guerra religiosa segue;))
ovelhas voando

@ Voando ovelhas - Você está mal informado. Você pode usar ()para instruções únicas. Tente entrar (1 to 9).map(i => {val j = i+1; i*j})no REPL e veja o que acontece se você o usar (1 to 9).map(i => (val j = i+1; i*j)).
Rex Kerr

verdade, mas eu apenas me referi a expressões e outras coisas. Desculpe, eu odeio escrever coisas sem poder usar quebras de linha;) #
flying sheep sheep

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

Provavelmente, isso poderia ser reduzido com a entrada de stdin, se isso fosse uma opção, mas é tarde e, de qualquer forma, ainda são 104 caracteres para a função em si.


4

Befunge-98, 38 31 bytes

Sei que esse é um desafio antigo, mas recentemente descobri as linguagens sleepsort e 2D, tive uma idéia de como combiná-las e procurei um lugar para publicá-las, então aqui estamos.

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

O IP principal lê um número ( &), depois atinge o tque o clona: continua-se na mesma linha e alterna ciclos, lendo novos números e gerando novos filhos até chegar ao EOF que termina a sequência. Todos os processos filho ficar preso em um circuito fechado (o ve ^da terceira coluna) até que termine a principal IP lendo a entrada e executa a seqüência de comandos '<21p, o que coloca o personagem <na posição (1,2), substituindo o ^e libertando todos os processos filhos, que iniciam o ciclo simultaneamente, reduzindo em 1 o número a cada iteração. Como a velocidade de execução de diferentes IPs é sincronizada no befunge, eles terminam (e imprimem seu valor) em ordem, classificando a lista de entrada.


26 bytes movendo o fluxo de controle um pouco.
Jo rei

3

Um pouco tarde para a festa:

Maple - 91 83 caracteres

Em 91:

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

Em 83:

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

(Isso precisa do Maple versão 15 e espera que a lista seja classificada em L)


3

C, 70 69 caracteres

Não espera que os processos filhos retornem, caso contrário, funciona.

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

2

PHP 57 bytes

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

pcntl_fork () está disponível apenas no linux.


2

Bash (38):

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

Editar: ponto flutuante de stdin, separados por espaços ou novas linhas.


2

Haskell, 90

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

Espero que isso atenda a todos os requisitos.



1

Apenas alguns ajustes da versão de @rmckenzie:

Início de thread atrasado do Python em 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 sem demora no 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()

Gerenciado mais algumas otimizações, usando em Timervez de Thread, que tem uma chamada mais concisa e removeu a necessidade de importar time. O método de início de encadeamento atrasado se beneficia da compreensão da lista, pois elimina a necessidade de inicializar a lista separadamente no início, embora seja dois caracteres mais ( "["+"]"+" "-":") que o loop for, portanto é inútil sem início atrasado e você deve ter cuidado ao usar uma lista em vez de um gerador, ou você não está criando os encadeamentos do timer até percorrer o gerador.

Alguém mais tem alguma otimização?


O truque com asajuda, mas no 2.7.1 você só pode importar um módulo para um pseudônimo, e depois de algumas brincadeiras sobre você não pode nem import mod1,mod2 as a,bprecisar, você precisa import mod1 as a, mod2 as b. Ele ainda salva alguns caracteres, mas não é exatamente a cura - tudo o que eu pensava que era ... E, na verdade, é melhor deixar o sistema como sistema. A segmentação por aliasing ainda ajuda ...


você me bateu, tenha uma vantagem. Eu gosto do x = []; x + = []. Não sabia que você poderia fazer isso ....
arrdem

... você poderia fazer isso em 128 se perder os espaços entre a: [declaração] em seu loop ef (x) ... de alguma forma eu consegui 127, mas acho que isso é não contando a nova linha final (que é legítimo no CG). Pensei em fornecer a atualização em vez de ser uma ferramenta e roubar seu código.
arrdem

@rmckenzie vá em frente, eu roubei o seu. Estou sempre interessado em ver CG'd python - Eu sinto que estou fazendo algo muito perverso considerando os objetivos da língua ...
theheadofabroom

Sim, estou sinceramente chocado com a legibilidade da maioria dos golfinhos-python ... ao custo de um "piso de vidro" de personagens. Verifique este: import threading, sys as t
arrdem

1

Clojure, 54

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


você pode se livrar de alguns caracteres inline omitindo defn(seus colchetes + lista de argumentos: de 54 a 43 chrs) ou use em fnvez de defn=> len- = 2, então eu diria no clj its 43: D
test30

1

Ferrugem - 150 bytes

E é por isso que você não codifica golfe no Rust, é mais detalhado que Java;). Depende da caixa externa crossbeam, seria ainda pior sem ela.

|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 teste 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 de porta chata de C #, apenas para começar a usar o idioma novamente:

F # - 90 caracteres

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

ou 71/65 caracteres com fora do padrão:

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

Mesmo em 2011, acho que function(a){a.map(function(v){setTimeout(console.log,v,v)})}pode ter funcionado em pelo menos um navegador por 60 bytes. Claro que hoje em dia você escreveria a=>a.map(v=>setTimeout(console.log,v,v)).
Neil

0

Tcl 8.6, 41 caracteres

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

Você tem que matá-lo com ^C


0

VB.NET 100 bytes

Como o VB.Net exige que as lambdas de linha única contenham apenas uma instrução, esse código precisa ter várias linhas:

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

No entanto, não tenho certeza se você conta as instruções de importação na contagem de bytes, porque se você não as contar, eu poderia escrever o seguinte:

VB.NET 71 bytes

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 bytes

Assume que os números são fornecidos na linha de comando ...

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


0

Mathematica, 34 ou 36 bytes

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

Basta anexar a lista a ser classificada no final deste código e avaliar. Se precisar ser uma definição de função válida, serão necessários dois bytes extras:

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

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

Ungolfed e 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;
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.