【小ネタ】JSで要素の組み合わせを列挙する


下記のような、キーの数や要素数が可変のデータの組み合わせを、列挙するjavascriptコードです。
pythonにはitertoolなどの順列・組み合わせ計算を行う定番ライブラリがあるようです。

やっている事ですが、イメージとしては組み合わせを数列に置き換えています。
1桁目が2進数、3桁目が3進数、3桁目が4進数の不規則な進法で表現されていると捉えて、
n[1..234=24]までループでひたすら列挙します。

var data = {
  "1.ドリンク": ["チャイ", "ラッシー"],
  "2.副菜": ["サモサ", "ティッカマサラ", "サブジ"],
  "3.主菜": ["バターチキン", "キーマ", "ダール", "マトン"]
}

// 実行毎に結果の出力順序が一意になるようにソート
var keys = Object.keys(data).sort();

// 組み合わせの総数を事前に計算
var total = 1;
for (var key in data) {
  total *= data[key].length;
}

var q, // 商, ループ中の配列で表現できない数
    r, // 余り, ループ中の配列で表現する数
    result = []; // 組み合わせを格納する配列

// 組み合わせの総数回ループして、n番目にどの組み合わせが来るかどうかを求める
for (var n=0; n < total; n++) {
  result[n] = {};
  q = n;

  // dataのキー毎にループして、どの要素を使うか決定
  for (i=0; i<keys.length; i++) {
    key = keys[i];

    // ループ対象の配列の要素数で割った余り = その配列で表現できる数
    r = q % data[key].length;

    // ループ対象の配列の要素数で割った商 = その配列で表現できない数
    q = Math.floor(q / data[key].length);

    result[n][key] = data[key][r];
  }
}

// 出力
for (var i=0; i < result.length; i++) {
   console.log(JSON.stringify(result[i]));
}

/*
0:{"1.ドリンク":"チャイ","2.副菜":"サモサ","3.主菜":"バターチキン"}
1:{"1.ドリンク":"ラッシー","2.副菜":"サモサ","3.主菜":"バターチキン"}
2:{"1.ドリンク":"チャイ","2.副菜":"ティッカマサラ","3.主菜":"バターチキン"}
3:{"1.ドリンク":"ラッシー","2.副菜":"ティッカマサラ","3.主菜":"バターチキン"}
4:{"1.ドリンク":"チャイ","2.副菜":"サブジ","3.主菜":"バターチキン"}
5:{"1.ドリンク":"ラッシー","2.副菜":"サブジ","3.主菜":"バターチキン"}
6:{"1.ドリンク":"チャイ","2.副菜":"サモサ","3.主菜":"キーマ"}
7:{"1.ドリンク":"ラッシー","2.副菜":"サモサ","3.主菜":"キーマ"}
8:{"1.ドリンク":"チャイ","2.副菜":"ティッカマサラ","3.主菜":"キーマ"}
9:{"1.ドリンク":"ラッシー","2.副菜":"ティッカマサラ","3.主菜":"キーマ"}
10:{"1.ドリンク":"チャイ","2.副菜":"サブジ","3.主菜":"キーマ"}
11:{"1.ドリンク":"ラッシー","2.副菜":"サブジ","3.主菜":"キーマ"}
12:{"1.ドリンク":"チャイ","2.副菜":"サモサ","3.主菜":"ダール"}
13:{"1.ドリンク":"ラッシー","2.副菜":"サモサ","3.主菜":"ダール"}
14:{"1.ドリンク":"チャイ","2.副菜":"ティッカマサラ","3.主菜":"ダール"}
15:{"1.ドリンク":"ラッシー","2.副菜":"ティッカマサラ","3.主菜":"ダール"}
16:{"1.ドリンク":"チャイ","2.副菜":"サブジ","3.主菜":"ダール"}
17:{"1.ドリンク":"ラッシー","2.副菜":"サブジ","3.主菜":"ダール"}
18:{"1.ドリンク":"チャイ","2.副菜":"サモサ","3.主菜":"マトン"}
19:{"1.ドリンク":"ラッシー","2.副菜":"サモサ","3.主菜":"マトン"}
20:{"1.ドリンク":"チャイ","2.副菜":"ティッカマサラ","3.主菜":"マトン"}
21:{"1.ドリンク":"ラッシー","2.副菜":"ティッカマサラ","3.主菜":"マトン"}
22:{"1.ドリンク":"チャイ","2.副菜":"サブジ","3.主菜":"マトン"}
23:{"1.ドリンク":"ラッシー","2.副菜":"サブジ","3.主菜":"マトン"}
*/

例のデータで言えば2 * 3 * 4通りの組み合わせを求めているので、
例えば15番目の組み合わせをを求める場合、「ドリンク」で表現できる要素の数=2で割ると
商が7、余りが1、…となり、
商の7 = 「副菜」以降で表現しなければならない数
余りの1 = 「ドリンク」で表現する数

よって「ドリンク」は配列の添字[1]の要素「ラッシー」を使うと決定できます。

同様にして、商の7を「副菜」で表現できる3で割ると
商が2、余りが1、…となり、
「副菜」は配列の添字[1]の要素「ティッカマサラ」を使います。

最後の主菜では、2 / 4
商は勿論0、余りは[2]となり、
「主菜の」は配列の添字2の要素の「ダール」に決定します。


DACエンジニア採用情報

  関連記事

tf
ディープラーニングで「顔が似ているAKB48のメンバーを教えてくれるbot」を構築

概要 こんにちは、システム開発部の中村です。 今回は、Facebook Messenger APIを利用して、 画像をアップロードすると、似ているAKB48のメンバーを教えてくれるbotを実装しました。 尚、ディープラーニングやTensorFlowそのものの解説というより、 「エンジンとしてディープ …

question
読み方がわからない技術用語 2015

英語圏での読み方を基本的には参考にしています。英語圏でも複数の読み方をしているケースもあるようなので、あくまでも参考程度。2015と書きながら、古い言葉も混じってますが。 async – えーしんく Alt – おると ASUS – えいすーす bower &#8 …

14391226325_8c35c2a652_z
D3.jsとその活用事例について

D3.jsとは? D3とは「Data Driven Document」の略で、データに基づいてドキュメントを操作するための JavaScript ライブラリです。 ご存知の方も多いと思いますが、ちょっとだけD3.jsの基本的な使い方、そして弊社プラットフォームでの利用についてご紹介したいと思います。 …

スクリーンショット 2015-07-31 16.41.25
【未経験からのRuby on Rails – 第3回】変数と定数

こんにちは。新卒1年目のmatsuariです。 今回はRubyに限らずプログラミングを学ぶ上で非常に重要となる「変数と定数」について、ご紹介していきます。 変数とは・・・ オブジェクトを一時的に格納しておく箱で、オブジェクトを識別するために利用します。 言葉だけでは理解が難しいかと思いますので、まず …

swift
iOS端末情報をTreasureDataに送るアプリをswiftで作ってみた。

はじめまして、2年目のOyamanです。 通常業務とは別のことになりますが、Swiftに触れる機会が少しあったので、スマホ関連の記事を書かせていただきます。 はじめに SwiftとTreasureDataのSDKを使って、 iOSの端末情報をTreasureDataへ送るアプリを作ってみます。 今回 …

androidsdk10
SDKってどうやって作ってるの?【Android編】

こんにちは。4度目の投稿です。 現在私はAndroidのSDKを開発しています。 javaにもAndroidにもSDKにも手を出したのは初めてなので、最初はそもそもSDKのイメージが湧かず、ふわふわした状態で始めました。 SDKと調べても「あるソフトウェアを開発するために必要なプログラムや文書などを …

promise
ECMAScript6を使ってみた ~「Promise」編

ECMAScript6とは 一応ちょっとだけ説明しておくと、 ECMAScript(エクマスクリプト)は、Ecma Internationalによって標準化されたスクリプト言語で、バージョン6が2015 年 6 月 17 日に標準仕様として発行されました。(以下、ES6と呼びます) ES6ではcon …

4
【未経験からのRuby on Rails – 第4回】Railsアプリケーション開発をしよう! 〜開発の準備編〜

こんにちは。新卒のmatsuariです。 Rubyについてまだまだ知るべきことはたくさんありますが、とにかく早くアプリを作りたい! ということで、今回はアプリ開発の準備に取り掛かっていきます。 Rubyはアプリを作成しながら、同時に学んでいきたいと思います。 Railsアプリケーション開発の準備《 …

no image
Angular.jsのvalueとfactoryの違いを考える

次のようなHTMLがあったとする。 valueとfactoryの違いを考える valueもfactoryもcontrollerから利用する値やfunctionを登録しておくのに使う。そのようなcontrollerの外部に登録されているfunction等をサービスと呼ぶ。たとえば、下記のようにplus …

no image
Polymer core-ajax の使い方

Polymerのcore-ajaxの使い方。 まずは、index.html my-topicsというCustom Elementに実際の処理を書く。JSONで、とあるサーバからデータを取得する、という想定。本当はJSONPで取りたかったんだけど、それは次回までの課題で… core-aja …