嘘です。 reduce() を使わずにやったのではなく、知らないから使えなかったんです。この記事に存在意義はあるのか、そう自問します。いやいいんだよ、無駄なものなんてないさ。そう自答します。
コードは下にあります。その下には GitHub で公開しているところへのリンクがあります。気が向けばメンテナンスするでしょう。
説明
おおよそ二つの部分に分かれています。 breaker と sorter です。 breaker では多次元配列をどんどん崩していきます。崩れた順番が保証できない気がしたので sorter でソートします。
breaker の要点は、自分で自分を呼び出す再帰関数であるところでしょう。自分に食わすための引数を自分で吐き出す。頭がこんがらがってしまいます。
sorter の要点は、breaker に付けさせた「各階層ごとの順番を持った配列」の扱いです。 join() した値でソートするのですが、順番に二桁以上があったりすると単純に join() した値は使えません。桁数に合わせて 0 で埋めて処理しています。
コード
function dimensionBreaker(multidimArray) {
let row = []
return breaker(multidimArray, [])
.then(rly => {
return sorter(rly)
})
function breaker(target, id) {
return new Promise(resolve => {
if (!Array.isArray(target)) {
resolve(row.push({"id": id, "not": target}))
}
else {
let promiseArray = []
for (let i in target) {
promiseArray.push(breaker(target[i], id.concat(i.toString())))
}
Promise.all(promiseArray)
.then(() => {
resolve(row)
})
}
})
}
function sorter(row) {
let digits = []
for (let i in row) {
for (let j in row[i].id) {
if (digits[j] === undefined) {
digits[j] = 0
}
digits[j] = Math.max(digits[j], row[i].id[j].length)
}
}
for (let i in row) {
for (let j in row[i].id) {
row[i].id[j] = `${"0".repeat(digits[j])}${row[i].id[j]}`.slice(1)
}
row[i].id.join("")
}
return row.sort((a, b) => a.id - b.id).map(rly => [rly.not])
}
}
追伸
コードの終わりのほうでインデントに全角スペースを使っています。はてなブログのお馬鹿さんがどうしても改行を理解してくれなくて、仕方なくやったのです。僕とはてなを許してください。