JavaScript
 Computer >> コンピューター >  >> プログラミング >> JavaScript

JavaScriptで数値をできるだけ近い値を持つn個に分割する方法


問題

JavaScriptで関数を作成することを考えます。この関数は、第1引数として数値 num を、第2引数として数値 parts を受け取ります。

関数は、num をちょうど parts 個の数値に分割し、次の2つの条件を満たす必要があります。

  • 各数値は互いにできるだけ近い値にすること
  • 可能であれば偶数にすること

なお、出力される数値の順序は重要ではありません。

たとえば、関数への入力が以下の場合を考えてみましょう。

入力

const num = 20;
const parts = 6;

出力

const output = [3, 3, 3, 3, 4, 4];

解き方のアプローチ

この問題は「できるだけ均等に分割する」という発想で解きます。まず num ÷ parts の商(小数点以下切り捨て)を基本値とし、全要素をその値で埋めます。合計が num に届かない分だけ、要素を先頭から順に1ずつ増やしていけば、すべての値の差が最大でも1の配列が得られます。

コード例

以下が実際のコードです。

const num = 20;
const parts = 6;
const splitNumber = (num = 1, parts = 1) => {
    let n = Math.floor(num / parts);
    const arr = [];
    for (let i = 0; i < parts; i++){
        arr.push(n)
    };
    if(arr.reduce((a, b)=> a + b,0) === num){
        return arr;
    };
    for(let i = 0; i < parts; i++){
        arr[i]++;
        if(arr.reduce((a, b) => a + b, 0) === num){
            return arr;
        };
    };
};
console.log(splitNumber(num, parts));

出力

[ 4, 4, 3, 3, 3, 3 ]

コードの解説

  • Math.floor(num / parts):割り算の商を小数点以下切り捨てで求め、基本となる値を取得します。20 ÷ 6 = 3.33… なので n = 3 となります。
  • 配列の初期化:基本値 nparts 回 push して [3, 3, 3, 3, 3, 3] を作成します。
  • 合計のチェック:reduce() で合計を計算し、すでに num と一致していればそのまま返します(割り切れるケースです)。
  • 余りの分配:合計が不足している場合、先頭から順に要素を1ずつ加算し、合計が num になった瞬間に配列を返します。余りは 20 − 18 = 2 なので、最初の2要素が 4 になります。

剰余演算を使ったより効率的な書き方

上記のコードは、ループのたびに reduce() で合計を再計算しているため、やや冗長です。%(剰余演算子)を使えば、余りの個数を一度に求められます。

const splitNumber = (num = 1, parts = 1) => {
    const n = Math.floor(num / parts);
    const rem = num % parts;
    return Array.from({ length: parts }, (_, i) => (i < rem ? n + 1 : n));
};
console.log(splitNumber(20, 6)); // [4, 4, 3, 3, 3, 3]

この実装では、余り rem の個数分だけ先頭側の要素を n + 1 にし、残りを n にするだけで、同じ結果を O(parts) の一回の処理で得られます。シンプルで可読性も高いため、実務ではこちらの書き方がおすすめです。


  1. 【JavaScript】数値の約数をすべて求める関数の実装方法

    はじめに本記事では、正の整数を1つ引数として受け取り、その数を余りなく割り切れるすべての数(約数)を配列として返すJavaScript関数の実装方法を解説します。問題の定義作成する関数は、正の整数を唯一の引数として受け取ります。そして、入力された数値を完全に割り切れるすべての数値を要素とする配列を構築して返す必要があります。例えばー入力が次の数値だった場合:const num = 12;期待される出力は以下のとおりです。const output = [1, 2, 3, 4, 6, 12];12の場合、1・2・3・4・6・12の6つの整数が12を割り切れるため、これらが約数となります。実装コード

  2. JavaScriptで文字列をできるだけ多くの部分に分割するアルゴリズム

    文字列処理のアルゴリズム問題としてよく知られている「Partition Labels」をJavaScriptで解いてみましょう。この記事では、各文字が1つの部分にしか現れないように、文字列をできるだけ多くの部分へ分割する方法を解説します。 問題の定義 まず、文字列 str を引数として受け取るJavaScript関数を作成します。この関数の目的は、以下の条件を満たすように文字列を可能な限り多くの部分に分割することです。 各文字(英字)は、最大でも1つの部分にしか出現しない 戻り値は、各部分の長さを表す整数の配列 例を見てみましょう。 入力: const str = ababcbacade