質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

2回答

1001閲覧

forループを変数の値に応じて重複させたい

shiratama215

総合スコア5

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

2クリップ

投稿2020/06/08 08:55

編集2020/06/08 09:40

例えばある変数の値が3のときは

Javascript

1for(--){ 2 for(--){ 3 for(--){ 4 } 5 } 6}

4のときは

Javascript

1for(--){ 2 for(--){ 3 for(--){ 4 for(--){ 5 ~処理内容~ 6 } 7 } 8 } 9}

といった感じで、可変する数に応じて重複してループする回数を変える方法はないでしょうか。

phpのfor文で強引にJavascriptのfor文を書くことで実現できました。

php

1for(--){ 2 echo "for(var i=0){"; 3} 4~処理内容~ 5for(--){ 6 echo "}"; 7}

できればブラウザ上で変化する値に応じて処理を変えたいので、Javascriptだけで記述したいです。
上手く伝わっているかわかりませんが、ご助力よろしくお願いします。

――追記――

配列の中の数値を2つ以上足した数値をすべて取り出したいです。
そしてこの配列の中の数値や個数が変化する前提で記述したいです。

Javascript

1 2var money = [500,100,100,50,10,5]; 3var pattern = []; 4 5for(i=0; i<money.length-1; i++){ 6 7 for(j=i+1; j<money.length; j++){ 8 sum = 0; 9 sum += money[i]; 10 sum += money[j]; 11 if(!pattern.includes(sum)){ 12 pattern.push(sum); 13 } 14 15 for(k=j+1; k<money.length; k++){ 16 sum = 0; 17 sum += money[i]; 18 sum += money[j]; 19 sum += money[k]; 20 if(!pattern.includes(sum)){ 21 pattern.push(sum); 22 } 23 24 for(l=k+1; l<money.length; l++){ 25 sum = 0; 26 sum += money[i]; 27 sum += money[j]; 28 sum += money[k]; 29 sum += money[l]; 30 if(!pattern.includes(sum)){ 31 pattern.push(sum); 32 } 33 34 for(m=l+1; m<money.length; m++){ 35 sum = 0; 36 sum += money[i]; 37 sum += money[j]; 38 sum += money[k]; 39 sum += money[l]; 40 sum += money[m]; 41 if(!pattern.includes(sum)){ 42 pattern.push(sum); 43 } 44 45 for(n=m+1; n<money.length; n++){ 46 sum = 0; 47 sum += money[i]; 48 sum += money[j]; 49 sum += money[k]; 50 sum += money[l]; 51 sum += money[m]; 52 sum += money[n]; 53 if(!pattern.includes(sum)){ 54 pattern.push(sum); 55 } 56 57 for(o=n+1; o<money.length; o++){ 58 sum = 0; 59 sum += money[i]; 60 sum += money[j]; 61 sum += money[k]; 62 sum += money[l]; 63 sum += money[m]; 64 sum += money[n]; 65 sum += money[o]; 66 if(!pattern.includes(sum)){ 67 pattern.push(sum); 68 } 69 } 70 } 71 } 72 } 73 } 74 } 75}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yambejp

2020/06/08 08:58

n重ループにするとして、その中でどうforを回すかがわからないとなんとも・・・
shiratama215

2020/06/08 09:14

目的は、個数が変化する配列の、すべての要素の組み合わせを出すことです。
takasima20

2020/06/08 09:17

再帰でいけるんじゃ? 処理内容しだいですが。
kei344

2020/06/08 09:20

そのまま使用できるデータを提示されたほうが回答を得やすいと思います。
shiratama215

2020/06/08 09:41

ご助言ありがとうございます。 コードを記載しました。
miyabi_takatsuk

2020/06/08 10:11 編集

takasima20さん > 逆に再帰使わないとできない気が。
ozwk

2020/06/08 11:14

これ配列の要素数をNとして 2^N-N-1通りですよね 使う使わないで2^N 1個しか使わないパターンがN通り 1個も使わないパターンが1通り
guest

回答2

0

こんにちは

以下、解決策になるかは分かりませんが、「これを試してみては?」というアイディアの提示になります。

ご質問にある、ループの階層数を表す変数を n とし、配列 money を集合(Mとします。)と考えると、得たい n 重のループによって走査される対象は、Mnデカルト冪 (nth Cartesian power) と考えられるかと思います。ですので、複数の配列から直積に相当する配列を作ってくれるライブラリを使うとよいかもしれません。探してみると、lodash のプラグインとして
lodash.product
を作ってくださっている方がおりますので、こちらを拝借しますと、以下のように書けます。

javascript

1_.product(...Array(n).fill(money))

以下は、n2, 3, 4 の場合に、直積の要素をConsoleに表示するサンプルです。

意図通り、直積の要素の個数は、money.length ** n となっていることが確認できます。以上参考になれば幸いです。

追記

コメントを拝読しまして、要件としては、直積ではなく組み合わせを求めることと把握しました。組み合わせを求めるロジックをご自身で書いても、もちろんよいのですが、lodash.combinations を使うこともできます。

これを使うと、たとえば以下

javascript

1_.combinations(money, 3)

によって、money の要素から3個選んだ組み合わせの配列が得られます。ですので、コメントから頂いた要件を満たすには、組み合わせに含まれる要素の数を 2 から money.length まで変えて、それぞれで得られる配列を連結すればよいかと思います。

以下は、上記の考えによるサンプルです。

上記のサンプルでは、各組み合わせでの要素の合計も表示しています。また、組み合わせの数としては

6C2 + 6C3 + 6C4 + 6C5 + 6C6 = 15 + 20 + 15 + 6 + 1 = 57

となっていることが確認できます。

追記2

ライブラリを使わないコードを追記しておきます。考え方としては、以下です。

  • [500, 100, 100, 50, 10, 5] を集合(Mとします)と考えます。この場合、インデクス1 と 2の要素は同じ 100 ですが、これらは別物と考えます。以下では便宜上 100___1__, 100___2__ と書きます。

  • 集合論一般として、集合M の部分集合を集めた、べき集合 Power(M)を作ることができます。

  • このPower(M)は、要素として、{5}, {500, 100_1, 100_2, 10}, {500, 100_1, 100_2, 50, 10, 5}などの、すべての組み合わせを含みます。

ご質問の要件を解決するコードは、配列 moneyを集合とみた場合のべき集合に相当する配列を作り、べき集合に含まれる要素の配列の中で、長さが2以上のものだけを抽出して、各々について合計を出せばよいです。

そこで、べき集合を作るコードを作成しました。

上記で作成した関数 powerSet を使うと、[500, 100, 100, 50, 10, 5]から2つ以上を選び、それらの合計値として作り出せる数を小さい順に並べた配列 totals は、以下によって得られます。

javascript

1const money = [500, 100, 100, 50, 10, 5]; 2const choices = powerSet(money.length).filter(ary => ary.length >= 2).map(a => a.map(i => money[i])); 3const totals = [...new Set(choices.map(ary => ary.reduce((s,v) => s + v)))].sort((v1, v2) => v1 - v2);

投稿2020/06/08 10:37

編集2020/06/10 12:45
jun68ykt

総合スコア9058

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

shiratama215

2020/06/08 10:56

いただきましたサンプルを拝見させていただきました。 ありがとうございます。 細かいことになってしまうのですが、 1つは組み合わせを配列としてではなく合計した値を取得したいです。 (これは配列として取得した後に要素を合計する処理を別で行えば解決すると思います。) 2つ目は、組み合わせる数をnとして与えると思うのですが、nは2から配列の要素数までのすべての数値で行いたいです。なので結局for文を使うというところに逆戻りしてしまうのではないかと思っています。 (これも各nで配列を取得したあとに1配列ずつやっていけばよいと思うのですが、2度手間になってしまう?) 3つ目は、このプラグインでは、同じ要素同士の組み合わせも入っているようなのですが、今回やりたいこととしては、例えばmoney[0]とmoney[0]という組み合わせは含みたくありません。 このような細かい設定ができるのかはわかりませんが、目的を達成するのもそうですが、プログラムの記述方法として可能かどうかを知りたい、というのもあるため、解決は見送らせていただきたいと思います。 ご丁寧に詳しく説明してくださったのに申し訳ありません。 他の方が教えてくださった再帰という方法が使えるかもしれませんので私自身でも試行錯誤してみたいと思います。
jun68ykt

2020/06/08 11:46

コメントありがとうございます。 頂きましたコメントの要件にそって、回答のほうに追記しました。参考になれば幸いです。
jun68ykt

2020/06/10 12:46

lodashなどのライブラリを使わないコード例を回答のほうに追記2として挙げておきました。
guest

0

ベストアンサー

こちらに、n子要素の配列からm個抜き出すときの組み合わせサンプルがあります。
せっかくなので流用させてもらうと。

投稿2020/06/08 10:59

yambejp

総合スコア116724

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yambejp

2020/06/08 11:04 編集

//kumiawaseはまるまる流用 function kumiawase(balls, nukitorisu){ var arrs, i, j, zensu, kumis; arrs = []; zensu = balls.length; if(zensu < nukitorisu){ return; }else if(nukitorisu == 1){ for(i = 0; i < zensu; i++){ arrs[i] = [balls[i]]; } }else{ for(i = 0; i < zensu - nukitorisu + 1; i ++){ kumis = kumiawase(balls.slice(i + 1), nukitorisu - 1); for(j = 0; j < kumis.length; j ++){ arrs.push([balls[i]].concat(kumis[j])); } } } return arrs; } var money = [500,100,100,50,10,5]; var results=[]; var n=2; // n枚以上の組み合わせ for(var i=n;i<money.length;i++){ results = results.concat(kumiawase(money,i)); } results=results.map(x=>x.reduce((y,z)=>y+z)).filter((i,j,k)=>k.indexOf(i)==j).sort((x,y)=>x-y); console.log(results.join(",")); //15,55,60,65,105,110,115,150,155,160,165,200,205,210,215,250,255,260,265,505,510,515,550,555,560,565,600,605,610,615,650,655,660,665,700,705,710,715,750,755,760 //41通りが表示されます
shiratama215

2020/06/08 11:30

ありがとうございます! 私の知識では何が起きているかよく分かりませんが、やりたいことが再現できました。 このコードからひも解いてきちんと知識として蓄えていきたいと思います。 ひとつだけ追加すると、このまま使用した場合ですと、 「配列の要素すべてを足した」パターンの取りこぼしがあったため、 26行目の for(var i=n;i<money.length;i++){ を for(var i=n;i<=money.length;i++){ に変更いたしました。 他のご提案やご助言をくださったみなさまにもこの場を借りて感謝申し上げます。 ありがとうございました。
yambejp

2020/06/08 11:53

あ、失礼しました。最大要素数は配列のlengthでしたね・・・ ご指摘の通りで間違いないと思います
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問