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

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

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

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

Q&A

2回答

584閲覧

数値をバランス良く分ける方法

miu_ras

総合スコア902

JavaScript

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

0グッド

1クリップ

投稿2021/12/14 14:45

編集2021/12/14 19:02

要素がn個の数列を、m個のグループに分けます。
この時、各グループの数の合計の差ができるだけ小さくなるようにしたいです。
各グループに振り分ける要素の個数はばらつきがあっても構いません。
配列は降順にソート済みとします。

下記のデータの例では、「18, 18, 19」にしたいです。とりあえず単純に、配列の先頭から順に常に合計値が一番小さいグループに加算するというロジックを書きました。これでもまぁまぁ動くのですが、データにより期待より差が大きくなってしまうことがあります。

ですので、もう少しいいロジックにしたいです。動くコードを書いていただけたら嬉しいですが、そうでなくともこういう考え方があるとか、方針のアドバイス等でも嬉しいです。よろしくお願いします。

JavaScript

1var data = [6, 6, 6, 6, 5, 5, 4, 3, 3, 3, 2, 2, 2, 2]; 2var num = 3; 3 4/* 5得たい結果の例1 = [ 6 [6, 6, 3, 3], // 18 7 [6, 5, 4, 3], // 18 8 [6, 5, 2, 2, 2, 2] // 19 9]; 10得たい結果の例2 = [ 11 [6, 5, 3, 3, 2], // 19 12 [6, 6, 2, 2, 2], // 18 13 [6, 5, 4, 3], // 18 14]; 15 16下記コードの実行結果 = [ 17 [6, 6, 3, 2, 2], // 19 18 [6, 5, 4, 2, 2], // 19 19 [6, 5, 3, 3] // 17 20]; 21*/ 22 23console.log("data =", data); 24console.log("num =", num); 25console.log(""); 26 27var result = balancer(data, num); 28console.log("result =", result); 29 30function balancer(data, num) { 31 var result = Array(num).fill([]); 32 var totals = Array(num).fill(0); 33 34 for (var i = 0; i < data.length; i++) { 35 var ii = totals.indexOf(Math.min.apply(null, totals)); 36 result[ii].push(data[i]); 37 totals[ii] += data[i]; 38 } 39 40 console.log("totals =", totals); 41 return result; 42} 43

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

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

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

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

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

guest

回答2

0

類似の問題:

  • Divide 1 to n into two groups with minimum sum difference

(1以上n以下の整数を、それぞれのグループの合計の差が最小になるような2つのグループに分けよ。)

回答コード例を参考にして、以下を作成してみました。

javascript

1const mean = data.reduce((total, v) => total + v) / num; 2const groups = [[], [], []]; 3 4let group1Sum = mean; 5let group2Sum = mean; 6 7for (let v of data) { 8 if (group1Sum - v >= 0) { 9 groups[0].push(v); 10 group1Sum -= v; 11 } else if (group2Sum - v >= 0) { 12 groups[1].push(v); 13 group2Sum -= v; 14 } else { 15 groups[2].push(v); 16 } 17}

javascript

1// 結果の出力 2groups.forEach(a => { 3 const sum = a.reduce((s, v) => s + v); 4 console.log(a, sum); 5});

出力結果:

[6,6,6] 18

[6,5,5,2] 18
[4,3,3,3,2,2,2] 19

???? codepen

所与のdataの内容がどのようなものであっても、上記のコードのほうがご質問にある

とりあえず単純に、配列の先頭から順に常に合計値が一番小さいグループに加算するというロジック

よりも良い結果を出すことができる(少なくとも、より悪い結果にはならない)ことの証明はすぐは考えつきませんでした。ですので参考に留めていただければと思います。

投稿2021/12/14 23:29

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

miu_ras

2021/12/15 12:35

コードありがとうございます。 ご提示のコードだとデータの後ろに調整をきかせやすい細かい数字があるときにはうまくいく可能性が高まる、そうでない場合には失敗する可能性が高くなるという感じですね。前のグループに大きい数字を詰めていくことになるので、偏りが大きくなり、調整がききにくくなってしまいます。 データが[6, 6, 6, 6, 5, 5, 4, 3, 3]のときには[12, 12, 20]となってしまい、全然ダメでした。ちなみに私のコードでは[15, 15, 14]となりました。グループが2つの場合用で、それ以外には通用しない方法かもしれませんね。
guest

0

動的計画法(Dynamic Programming)向きの問題のように見えます。
探せば見つかるかもしれません。

投稿2021/12/14 22:58

ppaul

総合スコア24666

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

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

miu_ras

2021/12/15 15:25 編集

動的計画法…。イチから勉強するのは少し大変そうですが、少し勉強してみます。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問