スリープソートを実装する


74

スリープソートは、インターネットで見つけた整数ソートアルゴリズムです。出力ストリームを開き、各入力番号に対して並列に、number秒遅延してその番号を出力します。遅延のため、最も大きい番号が最後に出力されます。私はそれが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

タスクは、選択したプログラミング言語の関数としてスリープソートを実装することです。競合状態などの同時実行要因を無視して、共有リソースをロックすることはできません。最短のコードが優先されます。関数定義はコード長にカウントされます。

入力リストは負でない整数のみに制限されており、入力リストの長さはかなり長い(少なくとも10個の数字をテストする)と予想されるため、競合状態は発生しません。競合状態が発生しないと仮定します。


3
長さには何が重要ですか?IOを含む完全なプログラムまたは関連するルーチンだけですか?
コンラッドルドルフ

8
これに関する問題。リストの順序によっては、最初の値が出力されるまでリスト全体を読み取らない場合があります。たとえば、読み取りに45秒かかる大きなリストで、最初の値は2、最後の値は1です。1を印刷するスレッドは、2が印刷された後に実行される場合があります。エラー:出力は適切にソートされなくなりました。いくつかの回避策があるかもしれません-リスト全体を読んだ後にスレッドを作成し、それらを開始します(しかし、それはゴルフに対してより長いコードにつながります)。誰かがこの潜在的な問題に対処するゴルフを提供できるのだろうか...私は試してみるつもりです。
トーマスオーエンズ

11
ちなみに、このアルゴリズムを本当に興味深いものにしているのは、実際のアプリケーションが実際に存在していることです。たとえば、DNAシーケンス(サンガーシーケンス)は、このようなものに依存して、DNAフラグメントをその長さに従ってソートします(より一般的には、すべての電気泳動が同様のことを行います)。違いは、シーケンスはコンピューターではなく物理的に実行されることです。
コンラッドルドルフ

12
私はみんなのパレードで雨を降らせるのは嫌いですが、これはおそらくO(N ^ 2)のように複雑さをOSスケジューラーにオフロードしませんか?
Random832

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では、または「say」機能が宣言されているprint場合、関数をに置き換えてsay、各インスタンスで文字を保存できることに注意してください。明らかにdie、フォークされたプロセスを終了し、出力を書き込むため、どちらも最短のソリューションのままです。


あなたは実行STILできる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文字(コマンドラインの解析などはなし)を呼び出しますが、Cで34文字だけ追加できるのは印象的です!
レックスカー

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
おそらく、正確性を損なうことなく、1000の代わりに10(または9)を掛けることで、2つまたは3つの文字を削ることができます。
コンラッドルドルフ

12
1秒が残ることを意図している場合、おそらく1e3代わりに使用できます。
ジョーイ

2
@Tomalakは、alertJavaScriptのブロッキング出力でpromptあり、JavaScriptのブロッキング入力であり、confirmJavaScriptのブロッキングバイナリ入力です。JSをコマンドラインで記述する場合、それらが使用する呼び出しになります。
zzzzBov

1
@zzzzBov、ブロッキング出力を使用することは、ほぼ確実にこのタスクにとって悪い考えです。
ピーターテイラー

2
@zzzzBov、私が心配しているのはそれらが呼び出される順序です-JS仕様がsetTimeout-enqueuedサンクが呼び出される順序について強力な保証がない限りです。
ピーターテイラー

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:3つのボックス(クワッド)があるはずです。2つはI / O変数(入力を取得し、それに書き込むと出力を出力します)、1つ⎕DLはスリープである関数の名前です。
マリナス

9

Erlangでの4つの試行:

コンソールへの出力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
OpenMP CコードのWithDegreeOfParallelism場合と同様に、これが機能するように指定する必要がありますnum_threads
コンラッドルドルフ

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プログラムに期待どおりの動作をさせたい場合は、再度スレッドに参加する必要があることに注意してください
もう1つのギーク

どうして?実行時間が最も長いスレッドは、プロセスを存続させます。
-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()

コマンドラインalaから入力を受け取ります

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

多くのpythonゴルフと同様に、コードが十分にコンパクトであるため、名前を短縮するために変数をエイリアシングしても文字が保存されません。

これは、sysをエイリアスし、両方をtとしてスレッド化するため、ファンキーです。したがって、sys.argvはt.argvになります。foo import *よりも短く、ネットキャラクターを節約できます!しかし、グイドは満足していないだろうと思う...

自己への注意-Cを学び、Pythonでゴルフをやめます。 聖なる牛これはCソリューションよりも短い!


なんとか微調整することはできましたが、コメントには書式がうまく表示されないため、独自の回答を作成しました。daemonこれをデーモンとして起動していない限り、設定する必要はありません。また、位置引数を使用する方が短くなります、esp。あなたのエイリアスの場合NoneN
theheadofabroom

ああ、最初のものは2.7.1の下では機能しません。j最終的にはFalse-一行でやりすぎた場合の副作用ですか?
theheadofabroom

たわごとは、同じエイリアスに複数のモジュールをインポートできることを知りませんでした-私は実際には、同じカスタムベースクラスの複数のサブクラスが別々のサブモジュールにあるという使用法を考えることができました。さらに30を削ることができれば、bashよりも短くなります...しかし、そうなるとは思いません。
-theheadofabroom

私が知らなかった理由は、あなたができないからです-私はそれを実行しようとしましたが、スレッドはエイリアスされず、単にスレッドと呼ばれています。tにエイリアスされているのはsysです...これを実行してみましたか?インポートしas t,s、次に使用するsために変更する必要がありますが、それぞれに余分な2文字ですsys
11

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>が有効であることを前提としています。すべてを1行に書き込むことで、いくつかの文字を保存できます。


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はまっすぐに設定してくれてありがとう。
真実性

クラスは非公開で、7文字節約できます。
ダニエルルバロフ

1
またthrows Throwablecatch句を宣言して削除することもできます。
ダニエルルバロフ

私はあなたが交換することにより2つのバイトを保存することができると思いますLong.parseLongLong.valueOf
ハイパーニュートリノ16

私はそれが6。5年だったことを知っていますが、あなたはいくつかの部分をゴルフすることができます:publicそして、final取り除くことができます。class M{public static void mainことができますinterface M{static void main(Javaの8+)。Long.parseLong(a)することができますnew Long(a)(結果として165バイト
ケビンCruijssen

5

Javascript-52文字

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

CodeGolf.SEへようこそ!特に、コードをコードとして表示するためにコードを4スペース分インデントします。編集ページのサイドバーに他の書式設定ヘルプがあります。
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)

{}1行にとどまるときに使用しないafaik 。
空飛ぶ羊

@flying sheep- {}1つのステートメントで省略できますが;、1行またはnoで区切られたものをグループ化するために必要です。また{}、場合によっては、if / elseを使用せずに複数行のステートメントを記述できます。
レックスカー

ああ、私はあなたがそれらを省略できることを意味しませんでしたが、()代わりにワンライナーに使用できることを。味の問題だと思う。(私は単にそれらを置き換える()ときに{}まったくサポートされない理由を本当に理解していません。多分すぐにJavaユーザーを疎外しないために)。Scalaはクールですが、インデントによってコードブロックを定義することは明らかに優れています。(そして、そう、宗教戦争が続きます;))
羊の飛翔

@flying sheep-情報が間違っています。()単一のステートメントに使用できます。(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バイト

これは古い挑戦であることは知っていますが、私は最近、sleepsortと2D言語の両方を発見し、それらを組み合わせる方法について考え、それを投稿する場所を探していたので、ここにいます。

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

メインIPは番号(&)を読み取り、次にそれtを複製するものにヒットします。同じ行とサイクルに進み、新しい番号を読み取り、EOFに到達してシーケンスを終了するまで新しい子を生成します。すべての子プロセスは、(閉ループで動けなくなるv^、メインIPが入力を読み込み、一連のコマンド実行が終了するまで、3列目の)'<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ループよりも2文字長い()ジェネレーターではなく、ジェネレーターをチャンクするまで実際にタイマースレッドを作成していません。

他に最適化はありますか?


トリックはas役立ちますが、2.7.1であなただけのエイリアスに一つのモジュールをインポートすることができ、そしてあなたについてのいくつかの演奏の後にさえすることができないimport mod1,mod2 as a,b、あなたがする必要はありimport mod1 as a, mod2 as b。それはまだいくつかの文字を保存しますが、私が思っていたすべての治療法ではありません...そして実際、sysをsysのままにしておく方が良いです。ただし、スレッド化のエイリアスはまだ役立ちます...


あなたは私を打たせて、騒動を起こします。私はx = []; x + = []が好きです。....あなたがそれを行うことができます知らなかった
arrdem

...ループ内の[文]とf(x)の間のスペースを失うと、128でこれを行うことができます...どういうわけか127になりましたが、それは最後の改行(これはCGでは合法です)。ツールになってコードを盗むのではなく、アップデートを提供すると思います。
arrdem

@rmckenzieはそれのために行きます、私はあなたのものを盗みました。私は常にCGされたpythonを見ることに興味があります
-theheadofabroom

ええ、私は正直、ほとんどのパイソンゴルフがどのくらい読みやすいかということにショックを受けています...キャラクターの「ガラスの床」を犠牲にして。これをチェックしてください:threading、sysを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)})}、少なくとも1つのブラウザーで60バイト使用できたと思います。もちろん、最近ではa=>a.map(v=>setTimeout(console.log,v,v))代わりに書くでしょう。
ニール


0

VB.NET 100バイト

VB.Netでは、1行のラムダに1つのステートメントのみを含める必要があるため、このコードには複数の行が必要です。

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}]&/@

ソートするリストをこのコードの最後に追加して、評価してください。有効な関数定義である必要がある場合、さらに2バイト必要です。

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;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.