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

JavaScriptで配列の組み合わせを文字列化し、出現頻度ランキングを生成する方法

本記事では、任意の個数の数値配列を受け取り、各要素やその組み合わせが全体の中で何回出現したかを集計した頻度マップ(オブジェクト)を返すJavaScript関数の作成方法を解説します。

やりたいことの確認

例えば、以下のように複数の配列が与えられたとします。

const a = [23, 45, 21], b = [45, 23], c = [21, 32], d = [23], e = [32], f = [50, 54];

このとき求めたいのは、単一の数値だけでなく、配列内の要素同士の組み合わせ(例:「23, 45」「21, 23, 45」など)も含めて、それぞれが何回登場したかをカウントしたオブジェクトです。イメージとしては次のようになります。

const output = {
    '21': 2,
    '23': 3,
    '32': 2,
    '45': 2,
    '50': 1,
    '54': 1,
    '23, 45': 2,
    '21, 23, 45': 1,
    '21, 32': 1,
    '50, 54': 1
}

ポイントは、組み合わせを「23, 45」のような文字列として連結したキーに変換しているところです。これにより、どんな組み合わせでもオブジェクトのプロパティとして一意に管理できるようになります。

実装コード

この処理を実現するコードは以下の通りです。

const a = [23, 45, 21], b = [45, 23], c = [21, 32], d = [23], e = [32], f = [50, 54];

// 配列からすべての組み合わせを生成する関数
const findMatch = arr => {
    let result = [];
    const pick = (i, t) => {
        if (i === arr.length) {
            t.length && result.push(t);
            return;
        };
        pick(i + 1, t.concat(arr[i]));
        pick(i + 1, t);
    };
    pick(0, []);
    return result;
};

// 昇順ソート用の比較関数
const sorter = (a, b) => a - b;

// 組み合わせを文字列キーに変換してカウントする関数
const mergeCombination = (arr, obj) => {
    findMatch(arr.sort(sorter)).forEach(el => {
        return obj[el.join(', ')] = (obj[el.join(', ')] || 0) + 1
    });
};

// 複数の配列を受け取って最終的な頻度マップを構築する関数
const buildFinalCombinations = (...arrs) => {
    const obj = {};
    for(let i = 0; i < arrs.length; i++){
        mergeCombination(arrs[i], obj);
    };
    return obj;
};

console.log(buildFinalCombinations(a, b, c, d, e, f));

コードの仕組み

1. findMatch:組み合わせの全列挙

findMatchは、配列の各要素について「選ぶ/選ばない」の2択を再帰的に繰り返すことで、すべての部分集合(組み合わせ)を生成する関数です。要素数nの配列に対して最大2^n通りの組み合わせが得られます。

2. sorter:組み合わせの順序を統一

(a, b) => a - bという比較関数で各配列を事前に昇順ソートしています。これにより、「45, 23」と「23, 45」のような順序違いの同じ組み合わせが、常に「23, 45」という同一のキーにまとめられるようになります。

3. mergeCombination:文字列キーでのカウント

生成された各組み合わせをjoin(', ')で文字列化し、オブジェクトのキーとして出現回数をインクリメントしていきます。obj[key] || 0というイディオムにより、初めて出現するキーでもエラーなくカウントを開始できます。

4. buildFinalCombinations:複数配列の一括処理

可変長引数(レスト構文...arrs)で受け取ったすべての配列に対してmergeCombinationを順番に適用し、結果を1つのオブジェクトに統合して返します。

実行結果

コンソールには次のように出力されます。

{
    '21': 2,
    '23': 3,
    '32': 2,
    '45': 2,
    '50': 1,
    '54': 1,
    '21, 23, 45': 1,
    '21, 23': 1,
    '21, 45': 1,
    '23, 45': 2,
    '21, 32': 1,
    '50, 54': 1
}

このように、単一要素・複数要素の組み合わせを問わず、すべての出現パターンを文字列キーで一括集計できることが確認できます。アンケートの回答履歴や購買データなど、「どの項目がどのセットで一緒に出現したか」を分析したい場面で活用できる便利なテクニックです。

  1. JavaScriptでアクセント付き文字を含む文字列を並べ替える方法

    JavaScriptの標準的な sort() メソッドは、文字列をUnicodeコードポイントの順序に基づいて比較します。そのため、「é」や「ó」のようなアクセント付き文字を含む文字列を単純にソートすると、期待通りのアルファベット順にならないことがあります。この問題を解決するには、localeCompare() メソッドを使用します。このメソッドは、指定されたロケールの言語規則に従って文字列を比較できるため、アクセント付き文字も正しく並べ替えられます。localeCompare() の基本的な使い方以下は、スペイン語のアクセント付き文字を含む配列を localeCompare() を使ってソー

  2. JavaScriptでテンプレート文字列をネストする方法

    JavaScriptのES6で導入されたテンプレート文字列(テンプレートリテラル)は、バッククォート(`)で囲むことで文字列の中に変数や式を埋め込める便利な機能です。実は、この${}(プレースホルダー)の中に、さらに別のテンプレート文字列を入れ子(ネスト)として記述することもできます。テンプレート文字列のネストとは${}の中には任意のJavaScript式を書けるため、その中で再度バッククォートを使ったテンプレート文字列を評価することが可能です。これにより、関数呼び出しの引数として動的に生成した文字列を渡すなど、柔軟な文字列組み立てが行えます。コード例以下は、ボタンをクリックすると、ネストされ