ユニークな素数の組み合わせ製品


21

問題の声明

一意の連続する素数(必ずしも2を含まない)のセットが与えられた場合、これらの素数の最初のべきのすべての組み合わせ(たとえば、繰り返しなし)と1の積を生成します。たとえば、{ 7}、{1、2、3、5、6、7、10、14、15、21、30、35、42、70、105、210}を生成します:

  1  =  1
  2  =  2
  3  =  3
  5  =  5
  6  =  2 x 3
  7  =  7
 10  =  2 x 5
 14  =  2 x 7
 15  =  3 x 5
 21  =  3 x 7
 30  =  2 x 3 x 5
 35  =  5 x 7
 42  =  2 x 3 x 7
 70  =  2 x 5 x 7
105  =  3 x 5 x 7
210  =  2 x 3 x 5 x 7

入力セットのカーディナリティがkの場合、出力セットに2 ^ k個のメンバーが含まれることに注意してください。

ルール/条件

  1. 任意の言語を使用できます。ソースコードの最小文字数を目指します。
  2. ソリューションは、完全なプログラムまたは完全な機能でなければなりません。関数は匿名にすることができます(言語が匿名関数をサポートしている場合)。
  3. ソリューションは、少なくとも2 ^ 31までの製品をサポートできる必要があります。製品が大きすぎて表現できない数値が渡された場合、整数オーバーフローの検出や処理について心配する必要はありません。ただし、計算の限界を述べてください。
  4. リストまたはセットを受け入れ、リストまたはセットを作成できます。入力はソートされていると想定できますが、ソートされた出力を生成する必要はありません。

バックグラウンド

これはいつ、またはなぜ有用ですか?非常に役立つ1つの場所は、乗数のテーブルを生成して、Square Forms Factorizationとして知られる整数ファクタリングアルゴリズムで並列にレースを行うことです。。そこで、奇数の乗数を試してみると、ハードセミプライムでアルゴリズムが失敗する(因子を見つける)確率が約50%減少します。したがって、16個の試行乗数のセットを並列に生成する生成素数{3、5、7、11}のセットでは、アルゴリズムはハードセミプライムで約2 ^ –16回失敗します。素数リストに13を追加すると、32個の試行乗数のセットが生成され、失敗の可能性が約2 ^ –32に減少し、追加の計算費用なしで結果が大幅に改善されます。同じ合計ステップ数でまだ答えを見つけることができます)。

回答:


18

Pure Bash、32バイト

eval echo \$[{1,${1// /\}*{1,}}]

コマンドライン引数として渡された入力リスト(単一スペースで区切られた)を読み取ります。

3つの異なるシェル拡張が使用されます。

  1. ${1// /\}*{1,}あるパラメータ展開にスペースを置き換える2 3 5 7}*{1,与えるために2}*{1,3}*{1,5}*{1,7\$[{1,および}]は、それぞれ開始と終了に追加されてを与え\$[{1,2}*{1,3}*{1,5}*{1,7}]ます。\$[バックスラッシュ・エスケープこの段階で算術膨張を実行しようとする試みを防止するためです。
  2. \$[{1,2}*{1,3}*{1,5}*{1,7}]あるブレース展開は通常、ブレースの展開はパラメーターの展開の前に行われるため、eval最初にパラメーターの展開を強制するために使用する必要があります。ブレース展開の結果は$[1*1*1*1] $[1*1*1*7] $[1*1*5*1] ... $[2*3*5*7]です。
  3. $[1*1*1*1] $[1*1*1*7] $[1*1*5*1] ... $[2*3*5*7]算術展開のリストであり、その後、評価されて必要な数のリストが得られます。

出力:

$ ./comboprime.sh "2 3 5 7"
1 7 5 35 3 21 15 105 2 14 10 70 6 42 30 210
$

3
心...吹き飛ばさ...すごい!
トッドリーマン14

WTFは...私が取得1 0
username.ak

@ username.akあなたの入力は何ですか?どのように入力しますか(コマンドライン引数?)。どのバージョンのbashを実行していますか?bash --version
デジタルトラウマ

12

CJam、13バイト

1aq~{1$f*+}/p

[2 3 5 7]STDINから配列(例:)を読み取ります。オンラインでお試しください。

無名関数は同じバイト数になります:

{1a\{1$f*+}/}

実行例

$ cjam <(echo '1aq~{1$f*+}/p') <<< '[]'
[1]
$ cjam <(echo '1aq~{1$f*+}/p') <<< '[2 3 5 7]'
[1 2 3 6 5 10 15 30 7 14 21 42 35 70 105 210]

使い方

1a               " Push R := [1].              ";
  q~             " Read an array A from STDIN. ";
    {     }/     " For each a ∊ A:             ";
     1$f*+       "     R += { ra : r ∊ R }     ";
            p    " Print.                      ";

4
うわー、それはすべてのサブセットを反復処理する賢い方法です。
マーティンエンダー14

9

ハスケル、22

解決策は匿名関数です:

map product.mapM(:[1])

使用例:

*Main> map product.mapM(:[1]) $ [2,3,5]
[30,6,10,2,15,3,5,1]

説明:
(:[1])番号を指定しxてlistを返す関数[x,1]です。
mapM(:[1])は、数値のリストを指定した関数であり(:[1])、それらの関数を関数にマップし、すべてのリストから要素を選択するためのあらゆる方法を返します。たとえば、mapM(:[1]) $ [3,4]最初に関数をgetにマッピングします[[3,1] , [4,1]]。次いで、可能な選択肢は、[3,4](両方の最初の番号を選択)[3,1] [1,4]し、[1,1]それを返します[[3,4],[3,1],[1,4],[1,1]]

次にmap product、すべての選択肢をマッピングし、その製品を返します。これは、必要な出力です。

この関数はその型が多相的であるため、すべての型の数値を操作できます。リストを入力するIntと、結果はリストになりますがInt、タイプのリストにも適用できますIntegerのリストを返しIntegerます。これは、オーバーフロー動作がこの関数ではなく、入力のタイプによって指定されていることを意味します(yay Haskellの表現型システム:))


いいね!数字のサイズに制限はありますか?
トッドリーマン14

1
@ToddLehmanいや。デフォルトの数値タイプはInteger、無制限の整数タイプです。またInt、32ビット整数もありますが、それはほとんど単なるレガシーです。
ジョン・ドヴォルザーク

実際には@JanDvorakはいですが、それは言うまでもありませんが型システムが大好きです:)。注目すべきもう1つの点は、匿名であるため、使用方法が問題になる場合があることです。
誇りに思ってhaskeller 14

8

Mathematica、18 17バイト

1##&@@@Subsets@#&

それは匿名関数です。のように呼ぶ

1##&@@@Subsets@#&[{2,3,5,7}]

そして、マーティンは驚くほど短い答えで急降下します!
トッドリーマン14

@ToddLehmanでは、これに勝るJの回答を待ちましょう。;)
マーティン・エンダー14

1
Mathematicaがクローズドソースでない場合、誰かがゴルフバージョンを書くことができます。×@@@𝒫@#無敵であるべきです。
デニス14

@Dennis Wolfram言語仕様はMathematicaとは独立して利用可能であり、1つまたは2つの(不完全な)オープンソース実装があると思います。UnicodeエイリアスバージョンのMathematicaの作成が数回提案されましたが、PPCGで非常に受け入れられるとは思いません。^^
マーティン・エンダー14

2
@MartinBüttnerお待たせしました:(*/@#~2#:@i.@^#)Jの16文字;)
algorithmshark 14年

4

更新:C(関数f)、92

関数としても、これはここで最も長いエントリです。Cの関数引数として未知の長さの配列を渡したのは初めてであり、引数がポインター(使用される構文に関係なく)。したがって、長さを示すには2番目の引数が必要です。

整数配列を設定して返すのはほぼ確実に長くなるので、出力を標準出力に保持しました。

ヒントをくれたデニスに感謝します。

f以下のテストプログラムの関数(不要な空白を除く92文字)を参照してください。

printfを介した出力

j;

f(int c,int*x){
  int p=1,i;
  for(i=c<<c;i--;p=i%c?p:!!printf("%d ",p))p*=(i/c>>i%c)&1?1:x[i%c];
}

main(int d,char**v){
  d--;
  int y[d];
  for(j=d;j--;)y[j]=atoi(v[j+1]);
  f(d,y);
}

配列ポインターを介した出力

j,q[512];

f(int c,int*x,int*p){
    for(int i=-1;++i-(c<<c);p[i/c]*=(i/c>>i%c)&1?1:x[i%c])i%c||(p[i/c]=1);
}

main(int d,char**v){
  d--;
  int y[d];
  for(j=d;j--;)y[j]=atoi(v[j+1]);
  f(d,y,q);
  for(j=1<<d;j--;)printf("%d ",q[j]);
}

C(プログラム)、108

不要な空白を除外します。

p=1,i;
main(int c,char**v){
  c-=1;
  for(i=c<<c;i--;i%c||(printf("%d ",p),p=1))(i/c>>i%c)&1||(p*=atoi(v[i%c+1]));
}

コマンドラインからの入力、標準出力への出力。Cはここで勝つつもりはありませんが、明日関数に変換してみます。

基本的に、すべて1<<cの素数の組み合わせを反復処理します。各ビットはi/c、製品内の特定の素数の有無に関連付けられています。「内部ループ」i%cは素数を実行し、0に達したi/c.ときの値に応じてそれらを乗算しi%c、積が出力され、次の「外部」反復のために1に設定されます。

奇妙なことに、printf("%d ",p,p=1)動作しません(常に1を出力します)。これは、aで値が使用され、printf後で同じブラケットで割り当てられたときに奇妙な動作を見たのは初めてではありません。この場合、2番目のコンマが引数の区切りとしてではなく、演算子として扱われる可能性があります。

使用法

$ ./a 2 3 5 7
1 2 3 6 5 10 15 30 7 14 21 42 35 70 105 210

Cは、引数が評価される順序を厳密に定義していません。特に、多くのC関数呼び出しには、右から左に評価される引数があります。
COTO 14

セクション6.5.2.2からのISO / IEC 9899:TC3[。]機能指名の評価のため、実引数、および実引数内の部分式が指定されていないので、それは機能のを注文したコンパイラにアップしています引数が評価されます。と-Wsequence-point-Wall、GCCは文句を言うでしょう。
デニス14

1. UBを気にしない場合は、変更c-=1c--たり使用したりすることもできi=--c<<cます(GCCで動作するようです)。2.両方の用途||三項演算子で置き換えることができますp=i%c?p:!!printf("%d ",p)p*=(i/c>>i%c)&1?1:atoi(v[i%c+1])
デニス

@Dennisヒントをありがとう!就寝直前に投稿したので、プログラムを実行するだけでした。c-=1私は見逃してはならないこのような基本的なゴルフですが、argv(プログラム名)i=..c<<cにGCC / cygwinで動作する余分な文字列があることを忘れていたため、簡単なバグ修正でしたが、オリジナルを残しましたそのままプログラムを作成し、関数に移動します。したがってsizeof、関数の引数として渡された配列では機能しないことを知りました。三項演算子に対するあなたの提案を関数に組み込みました。配列を返す簡単な方法がないので、標準出力への出力にこだわっています。
レベルリバーセント14

はい、関数の引数として渡された配列はポインターに減衰します。-Cでは、関数パラメーターとして結果を含む配列にポインターを渡すことは珍しくありません。質問は、あなただけの大きさ512の配列を渡すことができるようにあなたは、製品が2 ^ 31よりも小さくなっていることを想定することができると述べている
デニス・

3

Haskell、27バイト

これは、匿名関数としての@sudoのCJam応答のHaskell実装です。@proud haskellerの素晴らしいHaskellソリューションに勝るものはありませんが、とにかくここにドロップします。

foldr((=<<)(++).map.(*))[1]

説明: foldrバイナリ関数、値、およびリストを受け取ります。次に、次のように、リスト内の各コンスセルを関数のアプリケーションで置き換え、リストの最後を値で置き換えますfoldr f v [a,b,c] == f a (f b (f c v))。値はを含む1要素のリスト1で、バイナリ関数はf = (=<<)(++).map.(*)です。さて、f番号をとりn、機能作る(n*)ことで乗算があることn、それから、機能になりg = map(n*)、リストのすべての要素にその関数を適用し、フィードそれに機能(=<<)(++)。ここで、(++)連結関数であり、(=<<)あるモナドバインドこの場合にとり、(++)かつg、適用され、リストに取る関数を与えますg そのコピーに追加し、2つを連結します。

要するに[1]、で始まりn、入力リストの各番号について、現在のリストのコピーを取り、すべてをで乗算しn、それを現在のリストに追加します。


3

Python:55文字

f=lambda l:l and[x*l[0]for x in f(l[1:])]+f(l[1:])or[1]

各番号を順番に含めるか除外するかを選択して、製品を再帰的に生成します。


再帰的ソリューション!クール!
トッドリーマン14

and逆に合計を書くとスペースを落とせると思いますか?
-mathmandan

@mathmandanうん、うまくいきました、ありがとう。
-xnor

3

PARI / GP、26バイト

v->divisors(factorback(v))

長いバージョンが含まれます

v->divisors(prod(i=1,#v,v[i]))

(30バイト)および

v->divisors(fold((x,y)->x*y,v))

(31バイト)。

入力がセットではなく分解行列である場合、divisors単独で使用すると18バイトを保存できることに注意してください。ただし、セットを分解行列に変換するには18バイト以上かかるようです。(39バイトで直接v->concat(Mat(v~),Mat(vectorv(#v,i,1)))または24バイトを乗算してリファクタリングv->factor(factorback(v))することでそれを行うことができますが、誰でももっとうまくできますか?)


2

セージ– 36 34

基本的に、正しく理解できれば、MartinBüttnerのソリューションと同じです。コメントで述べたように、回答として投稿することもできます。

lambda A:map(prod,Combinations(A))

これは匿名関数であり、たとえば次のように呼び出すことができます。

(lambda A:map(prod,Combinations(A)))([2,3,5,7])

1
匿名関数にすることで2バイトを削ることができます(質問で許可されています)
誇りに思ってhaskeller 14

2

J(20)

これは、私が期待した以上に長くなりました。それでも、ハスケルよりも短いです!

*/@:^"1#:@i.@(2&^)@#

使用法:

    f=:*/@:^"1#:@i.@(2&^)@#
    f 2 3 5 7
1 7 5 35 3 21 15 105 2 14 10 70 6 42 30 210

これは素数だけでなく、あらゆる数のセットに対して機能します。また、配列にpostfixがある限り、素数のサイズに制限はありませんx2 3 5 7x


*/@#~2#:@i.@^#14バイトの代替です。
マイル


1

R、56バイト

r=1;for(i in 1:length(s))r=c(r,apply(combn(s,i),2,prod))

ここで、sがセット(およびリスト)であると考えています。さらに短くすることができると確信しています。なるほど。


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