【JavaScript】数値の相対的な大きさに基づいてオブジェクトをXL・L・M・Sの4グループに分類するアルゴリズム
問題の概要
例えば、次のようなオブジェクトを要素として持つ配列があるとします。
const arr = [
{'item1': 144},
{'item2': 0},
{'item3': 366},
{'item4': 15},
{'item6': 366},
{'item7': 19},
{'item8': 211},
{'item9': 121}
];
ここで必要となるのは、このような配列を引数として受け取り、各オブジェクトを「XL」「L」「M」「S」の4つのグループに振り分けるJavaScript関数です。
ポイントは、分類の基準が数値そのものの絶対的な大きさではなく、配列内での相対的な大きさであるという点です。
アルゴリズムの考え方
まず配列内のすべての数値から最大値を求め、その最大値を基準に4段階の閾値を設定します。
- XL: 最大値(max)
- L: 最大値の75%(max × 3/4)
- M: 最大値の50%(max ÷ 2)
- S: 最大値の25%(max ÷ 4)
あとは各数値がどの閾値の区間に属するかを判定し、対応するグループの配列へ追加していくだけです。
実装コード
上記の考え方を実装すると、次のようになります。
const arr = [
{'item1': 144},
{'item2': 0},
{'item3': 366},
{'item4': 15},
{'item6': 366},
{'item7': 19},
{'item8': 211},
{'item9': 121}
];
const compareWithRange = (rangeArr, num) => {
for(let i = 0; i < rangeArr.length; i++){
if(num <= rangeArr[i] && num > rangeArr[i + 1]){
return i;
};
};
return rangeArr.length - 1;
}
const groupBySize = (arr = []) => {
const mapping = arr => arr.map(el => el[Object.keys(el)[0]]);
const max = Math.max(...mapping(arr));
const range = {
'XL': max,
'L': (max * 3) / 4,
'M': (max / 2),
'S': (max / 4)
};
const legend = ['XL', 'L', 'M', 'S'];
const res = {};
arr.forEach(el => {
const num = el[Object.keys(el)[0]];
const index = compareWithRange(Object.keys(range).map(key => range[key]), num);
const size = legend[index];
if(res.hasOwnProperty(size)){
res[size].push(Object.keys(el));
}
else{
res[size] = [Object.keys(el)];
}
});
return res;
};
console.log(groupBySize(arr));
出力結果
コンソールには以下のように出力されます。
{
M: [ [ 'item1' ], [ 'item9' ] ],
S: [ [ 'item2' ], [ 'item4' ], [ 'item7' ] ],
XL: [ [ 'item3' ], [ 'item6' ] ],
L: [ [ 'item8' ] ]
}
コードの解説
処理の流れを簡単に整理しておきましょう。
- compareWithRange(): 渡された数値がどの閾値区間に含まれるかを判定し、そのインデックスを返します。最後の区間では比較対象となる次の閾値が存在しないため条件を満たさず、ループを抜けた後に最後のインデックス(rangeArr.length - 1)を返すことで、最小側の数値も確実に「S」へ分類できるようになっています。
- groupBySize(): まず各オブジェクトから最初のプロパティの値(数値)だけを取り出して最大値を算出し(Math.max(...mapping(arr)))、それをもとに「XL」「L」「M」「S」の4つの閾値を持つrangeオブジェクトを定義します。
- 続いてforEachで全要素を走査し、判定結果のサイズ名をキーとして、結果オブジェクトresにアイテム名を格納していきます。
今回の例では最大値が366なので、各閾値は「L=274.5」「M=183」「S=91.5」となります。したがって、366のitem3とitem6は「XL」、211のitem8は「L」、144と121のitem1・item9は「M」、0・15・19のitem2・item4・item7は「S」に分類される、という仕組みです。
-
JavaScriptで数値配列の分散を計算する方法
問題昇順にソートされた数値の配列を受け取り、その分散(Variance)を計算するJavaScript関数を作成する必要があります。分散とは、一連の数値が平均値からどれだけばらついているかを表す統計量で、まず平均値を求め、その平均との差の二乗和をデータ数で割ることで計算できます。計算式まず、平均値(M)は次のように定義されます。$Mean (M) = ( \sum_{i=0}^{n-1} arr[i])$ / n続いて、分散(V)は各要素と平均値の差を二乗し、それらを合計してデータ数で割った値になります。Variance (V) = $(\sum_{i=0}^{n-1} (arr[i] - M
-
JavaScriptで配列を降順に並べ替えて隣接要素の差の合計を求める方法
問題 整数の配列を受け取るJavaScript関数を作成する必要があります。この関数は、配列を降順に並べ替えたうえで、隣り合う要素同士の差を順番に足し合わせ、その合計値を返すものです。 たとえば、次のような配列が渡された場合を考えてみましょう。 [6, 2, 15] この場合、期待される出力は次のとおりです。 (15 - 6) + (6 - 2) = 13 解決のアプローチ この問題は、以下の手順でシンプルに解くことができます。 sort()メソッドを使い、配列を降順(大きい順)に並べ替える。 隣接する2つの要素(i番目と i + 1 番目)の差を計算し、合計に加算していく。 配列の要素