LANG SELRCT

コードを書く場所についてはこちら

2018年5月1日火曜日

配列内の要素の組み合わせを列挙する(ペアのパターン)


["いちご", "めろん", "もも", "ぶどう"]

という配列の要素から2つ取り出した時の組み合わせ(nCr)のパターンを列挙してみる


このような感じで
[
  [いちご めろん, いちご もも, いちご ぶどう],
  [めろん もも, めろん ぶどう],
  [もも ぶどう]
]


簡単に書けそうな気がして書いてみたら意外と考えさせられました

その1とその2の実行結果は同じです



組み合わせのパターンの数だけを出す場合



コードを書かずにすぐに使えるデモもほしくて作りました


(このデモはブログに直接HTML/CSS/JSを書いたもの)




上の入力エリアに

いちご
めろん
もも
ぶどう

と入れてget pairsボタンをクリックすると
下の出力エリアに半角スペースでつながった2つのワードのパターンが出力される

いちご めろん,いちご もも,いちご ぶどう,めろん もも,めろん ぶどう,もも ぶどう


デモの入力例


.gs内でパターンのログを出してみる

コードの例 その2


下にあるその1よりも短く書いたコード


コード2.gs
function get2word_patterns() {
  var array = ["いちご", "めろん", "もも", "ぶどう"];
  var patterns = [];
  for (var a = 0; a < array.length - 1; a++) {
    var pattern = [];
    for (var i = a; i < array.length - 1; i++) {
      var head = array[a];
      var add = array[i + 1];
      pattern.push(head + " " + add);
    }
    patterns.push(pattern);
    pattern = [];
  }
  Logger.log(patterns);
}
意訳
この機能がやること
配列を用意する
結果を入れるpatterns配列を用意する
array配列-1だけ繰り返す
途中結果を入れるpattern配列を用意する
iにaを入れてarray配列-1より小さければiを足して以下を繰り返す
array配列のa番目と
array配列のi+1番目を
半角スペースでつないでpatternに追加する

patterns配列にpatternを追加して
pattern配列を空に戻して

出来上がったpatternsをログに出す




コードの例 その1


コード1.gs
function get2word_patterns() {
  var original = ["いちご", "めろん", "もも", "ぶどう"]
  var array = original.slice();
  var patterns = [];
  var pattern = [];
  var parent = array.shift();
  var childs = array.slice();
  
  var i = 0;
  while(i < original.length-1){
    if(childs != ""){
      var child = childs.shift();
      pattern.push([parent + " " + child]);
    }else{
      patterns.push(pattern);
      pattern = [];
      parent = array.shift();
      childs = array.slice();
      i++;
    }
  }  
  Logger.log(patterns);
}
意訳
この機能がやること
originalという名で配列を用意して
その配列をsliceでコピーする
patternsの入れ物
patternの入れ物
array配列の先頭を抜き出してparentに入れて
先頭を抜き出したarray配列の残りをchildsに入れて

iの初期値は0
iがoriginalの長さ-1より小さい限り以下を繰り返す
もしchilds配列が空じゃなければ
childs配列の先頭を抜き出して
patternにparent childを半角スペースでつなげて追加する
childs配列が空になったら
patternsにpatternを追加して
patternを空に戻して
array配列の先頭を抜き出してparentに入れて
先頭を抜き出したarray配列の残りをchildsに入れて
iをカウントアップしていく


出来上がったpatternsをログに出す



実行結果


HTML ServiceでUIを作ってみる


コード.gs
function doGet() {
  return HtmlService.createHtmlOutputFromFile('index');
}
意訳
この機能がやること
指定したHTMLファイルを表示する




index.html
<!DOCTYPE html>
<html>
<head>
  <style>
    .ta {
      width: 360px;
      height: 240px;
    }
  </style>
</head>
<body>
  <textarea id="INPUT_VALUE" class="ta"></textarea>
  <br>
  <button id="BT">get pairs</button>
  <br>
  <textarea id="OUTPUT_VALUE" class="ta"></textarea>
  <script>
    var INPUT_VALUE = document.getElementById("INPUT_VALUE");
    var OUTPUT_VALUE = document.getElementById("OUTPUT_VALUE");
    var BT = document.getElementById("BT");
    
    BT.onclick = get2word_patterns;
    
function get2word_patterns() {
  var array = INPUT_VALUE.value.split("\n");
  var patterns = [];
  for (var a = 0; a < array.length - 1; a++) {
    var pattern = [];
    for (var i = a; i < array.length - 1; i++) {
      var head = array[a];
      var add = array[i + 1];
      pattern.push(head + " " + add);
    }
    patterns.push(pattern);
    pattern = [];
  }
  OUTPUT_VALUE.value = patterns.toString()
}
  </script>
</body>
</html>
意訳
 



taのスタイル
幅
高さ




入力エリア

実行ボタン

出力エリア

INPUT_VALUEの要素を取得
OUTPUT_VALUEの要素を取得
BTの要素を取得

BTをクリックしたらget2word_patternsを実行する

この機能がやること
配列を用意する
結果を入れるpatterns配列を用意する
array配列-1だけ繰り返す
途中結果を入れるpattern配列を用意する
iにaを入れてarray配列-1より小さければiを足して以下を繰り返す
array配列のa番目と
array配列のi+1番目を
半角スペースでつないでpatternに追加する

patterns配列にpatternを追加して
pattern配列を空に戻して

出来上がったpatternsをログに出す






補足


コードだけ見てるとよくわからなくなってきたので
コード1.gsの方を例に何をやっているのか書き出してみる


どっちが前でどっちが後ろかの順番は関係なくペアのパターンを作りたい

用意する配列の例
original
["いちご", "めろん", "もも", "ぶどう"]

その配列をshiftして行くので、その前にオリジナルを残しておく→.slice()でコピーを作れる(シャローコピー)
array = original.slice()
["いちご", "めろん", "もも", "ぶどう"]

要素のペアを作りたいので、順番に要素を抜き出してペアを作っていく
そのためにarrayをshiftしてまずは0番目を抜き出し、そこに残りの要素をくっつけていく
parent = array.shift()
"いちご"
残りのarrayは["めろん", "もも", "ぶどう"]

childs = array.slice()
["めろん", "もも", "ぶどう"]

originalの要素数は4つだけど最後の"ぶどう"は後ろにくっつける要素がないので-1
for(var i = 0; i < original.length-1;){

後ろにくっつける要素がある限り
if(childs != "")

childsの中からひとつずつ要素を抜き出して
child = childs.shift()
→"めろん"
→残りのarrayは["もも", "ぶどう"]

parentとchildをセットにしてpatternに追加していく
pattern.push([parent, child]);
→"いちご", "めろん"

後ろにくっつける要素がなくなったら
}else{

ここまでに作ったpattern配列をpatterns配列に追加する
patterns.push(pattern)
→[["いちご", "めろん"], ["いちご", "もも"], ["いちご", "ぶどう"]]

次のpatternを作るためにpattern配列を空に戻して
pattern = []

次のparentをarray["めろん", "もも", "ぶどう"]から抜き出して
parent = array.shift()
→"めろん"

残りのarrayは["もも", "ぶどう"]なので
childs = array.slice()
でコピー
→["もも", "ぶどう"]

これを繰り返してすべてのペアを作って

出来上がったパターンをログに出す