LoginSignup
1
1

More than 5 years have passed since last update.

JavaScript 多次元配列の1次元配列への展開

Last updated at Posted at 2017-08-10

関数を作っていて、こんな機能があったらいいなと思いました。

function(a, b, c, d, e);
function([a, b, c, d, e]);
function([a, b], [c, d], e);
function([a, [b, c], d], e);
function([a, [b, [c], d], e);

これらの全てで同じように動く機能。

引数、argumentsを、配列に変換する方法は
Array.prototype.slice.call(arguments)
このようにすればいいことは以前から知っていますが、
結局のところ、そこから、多次元配列を1次元配列に変更しなければいけないと思ったので、実装してみました。

多次元配列から1次元配列への展開

  var arrayMultiDimensionExpand = function (arrayValue) {
    var result = [];
    var f = function (value) {
      for (var i = 0, l = value.length; i < l; i += 1) {
        var arrayItem = value[i];
        if (Array.isArray(arrayItem)) {
          f(arrayItem);
        } else {
          result.push(arrayItem);
        }
      }
    };
    f(arrayValue);
    return result;
  };

内部で再起呼び出しを使って出力しています。

動作確認

動作確認は次のとおりです。
世界最小テストフレームワークのcheckを使っています。

  var check = function (a, b, message) {
    if (a === b) {
      return true;
    }
    if ((typeof message === 'undefined')
    || (message === null)) {
      message = '';
    } else {
      message = 'Test:' + message + '\n';
    }
    message = message +
        'A != B' + '\n' +
        'A = ' + a + '\n' +
        'B = ' + b;
    alert(message);
    return false;
  };

  check('1,2,3,4',          arrayMultiDimensionExpand([1,2,3,4]).join());
  check('1,2,3,4',          arrayMultiDimensionExpand([[1,2],3,4]).join());
  check('1,2,3,4',          arrayMultiDimensionExpand([[1,2],[3,4]]).join());
  check('1,2,3,4,5,6',      arrayMultiDimensionExpand([1,2,3,4,5,6]).join());
  check('1,2,3,4,5,6',      arrayMultiDimensionExpand([[1,2],[3,4], 5, 6]).join());
  check('1,2,3,4,5,6',      arrayMultiDimensionExpand([[1,2,3,4], 5, 6]).join());
  check('1,2,3,4,5,6',      arrayMultiDimensionExpand([[1,[2,3],4], 5, 6]).join());
  check('1,2,3,4,5,6',      arrayMultiDimensionExpand([[[1,[2,3]],4], [5, 6]]).join());
  check('1,2,3,4,5,6',      arrayMultiDimensionExpand([[[[[[1],2],3],4],5],6]).join());
  check('1,2,3,4,5,6,7,8',  arrayMultiDimensionExpand([[1,[2,3],4], [5, [6, 7], 8]]).join());

これで、多次元配列で引数を渡されても、対応できる関数を作ることができます。

全文

全文です。
web と node.js と windows wsh wsf で動作確認しました。

orValue という、第一引数と、第二引数以降のものを比較する関数を作って、動作確認しました。
orValueは、第一引数に関数を指定すると、第二引数以降が展開されてしまうので、比較できないですね。

script.js
var alert = alert || function (message) {
    console.log(message);
};

var main = function (testName) {

  //----------------------------------------
  //・assert関数
  //----------------------------------------
  //  ・  value が true でなければ
  //      例外を出力する関数
  //  ・  他言語でよく使う
  //----------------------------------------
  var assert = function (value, message) {

    if ((typeof message === 'undefined')
    || (message === null)) {
      message = '';
    }
    if (typeof value !== 'boolean') {
      throw new Error('Error:' + message);
    }
    if (!value) {
      throw new Error('Error:' + message);
    }
  };

  //----------------------------------------
  //・check関数
  //----------------------------------------
  //  ・  2値が一致するかどうか確認する関数
  //----------------------------------------
  var check = function (a, b, message) {
    if (a === b) {
      return true;
    }
    if ((typeof message === 'undefined')
    || (message === null)) {
      message = '';
    } else {
      message = 'Test:' + message + '\n';
    }
    message = message +
        'A != B' + '\n' +
        'A = ' + a + '\n' +
        'B = ' + b;
    alert(message);
    return false;
  };

  //----------------------------------------
  //・Array.isArray
  //----------------------------------------
  //  ・Array.isArray が存在しない環境(WSHなど)
  //    のために実装
  //  ・参考:書籍:JavaScriptパターン P51
  //----------------------------------------
  Array.isArray = Array.isArray || function (arg) {
    return Object.prototype.toString.call(arg) === '[object Array]';
  };

  var arrayMultiDimensionExpand = function (arrayValue) {
    var result = [];
    var f = function (value) {
      for (var i = 0, l = value.length; i < l; i += 1) {
        var arrayItem = value[i];
        if (Array.isArray(arrayItem)) {
          f(arrayItem);
        } else {
          result.push(arrayItem);
        }
      }
    };
    f(arrayValue);
    return result;
  };

  check('1,2,3,4', arrayMultiDimensionExpand([1,2,3,4]).join(), '01');
  check('1,2,3,4', arrayMultiDimensionExpand([[1,2],3,4]).join(), '02');
  check('1,2,3,4', arrayMultiDimensionExpand([[1,2],[3,4]]).join(), '02');
  check('1,2,3,4,5,6', arrayMultiDimensionExpand([1,2,3,4,5,6]).join(), '02');
  check('1,2,3,4,5,6', arrayMultiDimensionExpand([[1,2],[3,4], 5, 6]).join(), '02');
  check('1,2,3,4,5,6', arrayMultiDimensionExpand([[1,2,3,4], 5, 6]).join(), '02');
  check('1,2,3,4,5,6', arrayMultiDimensionExpand([[1,[2,3],4], 5, 6]).join(), '02');
  check('1,2,3,4,5,6', arrayMultiDimensionExpand([[[1,[2,3]],4], [5, 6]]).join(), '02');
  check('1,2,3,4,5,6', arrayMultiDimensionExpand([[[[[[1],2],3],4],5],6]).join(), '02');
  check('1,2,3,4,5,6,7,8', arrayMultiDimensionExpand([[1,[2,3],4], [5, [6, 7], 8]]).join(), '02');

  var orValue = function (value, compares) {

    assert(2 <= arguments.length);
    var argsArray = arrayMultiDimensionExpand(arguments);

    for (var i = 1, l = argsArray.length; i < l; i += 1) {
      if (value === argsArray[i]) {
        return true;
      }
    }
    return false;
  };

  var a = 1;
  check(true, orValue(a, 1), '01');
  check(true, orValue(a, 1, 2), '02');
  check(true, orValue(a, 1, 2, 3), '03');
  check(false,orValue(a, 2, 3, 4), '04');

  check(true, orValue(101, [101, 102]));
  check(true, orValue(102, [101, 102]));
  check(false,orValue(103, [101, 102]));
  check(true, orValue(103, [101, 102], 103));
  check(false,orValue(104, [101, 102], 103));
  check(true, orValue(104, [101, 102], 103, 104));
  check(true, orValue(104, [101, 102], [103, 104]));

  check(false,orValue(105, [101, 102], [103, 104]));
  check(true, orValue(105, [101, 102], [103, 104], 105));
  check(true, orValue(102, [[[101, [102], 103], 104], 105]));
  check(true, orValue(103, [[[101, [102], 103], 104], 105]));
  check(true, orValue(105, [[[101, [102], 103], 104], 105]));
  check(false,orValue(106, [[[101, [102], 103], 104], 105]));


  alert(testName + ' test finish');
}

if (typeof module !== 'undefined') {
  module.exports = main;
}

index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title></title>
    <script src="script.js"></script>

<script>

var alert = function (message) {
    console.log(message);
};

window.addEventListener("load",function(eve){
  // main('load');
},false);

</script>

  </head>
<body>

<form name="form01">
<table class="table02">
  <tr>
    <td>
      <input type="button" value="Test01" onclick="main('web')" 
        style="width:150px;">

    </td>
  </tr>

</table>
</form>


</body>
</html>

call_script_node.js
var main = require('./script.js');
main('node.js');
run_node_script.bat
node call_script_node.js
pause
run_wsh_script.wsf
<?xml version="1.0" encoding="shift-jis" ?>
<job>
    <script language="JavaScript" src=".\script.js"></script>
    <script language="JavaScript">
    <![CDATA[

var alert = function (message) {
    WScript.Echo(message);
}

main('WSH_wsf');

    ]]>
    </script>
</job>

ライブラリ

このあたりの仕組みなどを組み込んだ、汎用関数ライブラリを作っています。
既存のJavaScript環境の(たぶん)全てに対応できるように組んでいるので、
ご参考や、ご利用など、どうぞです。

stsLib.js/Source/stsLib.js at master · standard-software/stsLib.js
https://github.com/standard-software/stsLib.js/tree/master/Source/stsLib.js

追記

........もしかして......
joinして、splitしたら、同じ処理ができるのではないか???

多次元配列に対して、[1,2,3,[4,5, [6,7]]].join()
は、かなりいい感じの値を返してくれている。

必要なら調べてみてください。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1