// Question from // https://twitter.com/RplusTW/status/1498288300934971401 // inspired from @esp10mm // want to get all order => [a, c, b, d] genOrder([ ['c', 'b'], ['a', 'b', 'd'], ['a', 'c'], ]); function genOrder(data) { var relations = data.reduce((all, i) => { let prevChars = []; i.forEach(j => { if (!all[j]) { all[j] = { value: j, prev: [], }; } // collect prev chars & remove dup item all[j].prev = [...new Set(all[j].prev.concat(prevChars))]; prevChars.push(j); }); return all; }, {}); // { // "c": { "value": "c", "prev": ["a"] }, // "b": { "value": "b", "prev": ["c", "a"] }, // "a": { "value": "a", "prev": [] }, // "d": { "value": "d", "prev": ["a", "b"] } // } let calcOrder = (prevArr) => { if (!prevArr.length) { return 0; } return prevArr.reduce((all, i) => { return all + getOrder(i); }, 1 /* base */); } // reduce duplicated calc, but pass order = 0 let getOrder = (char) => { let order = relations[char].order ?? -1; if (order === -1) { order = relations[char].order = calcOrder(relations[char].prev) ; } return order; } for (let i in relations) { relations[i].order = calcOrder(relations[i].prev); } return Object.values(relations) .sort((a, b) => a.order - b.order) .map(i => i.value); }