4

In Javascript, how to convert a single dimensional array into a multidimensional array of unspecified depth or length.

Example:

let input = ['a','b','b','b','a','a','b','b','b','c','c','a','a','b','b'];
const makeMatrix = () => {}

let output = makeMatrix(input);

// output: ['a',['b','b','b'],'a','a',['b','b','b',['c','c']],'a','a',['b','b']]

What should the makeMatrix function look like to accomplish this task? Assume that values always move in a linear forward direction, but might possibly cut backward. So a always leads to b. An a would never hop to c. But c might drop back down to a.

This is to try to convert heading elements into a table of contents. Making a simple single tier toc is easy, but making a multi tiered one is wracking my brain. I have looked through a number of solutions, but have not seen anything that solves this particular problem.

8
  • Would a solution involving an array of numbers also be useful to you? Commented Dec 24, 2018 at 18:58
  • What is the process to convert the input exactly? It looks like you want to 'a' to be at level 1, 'b' at level 2, 'c' at level 3, etc. If so I think the simplest way is to simply create a string starting with "[" , keep track of the current depth of array you're in (starting with 1) and on each character add "[" or "]" respectively to make it so you're on the correct level for the character then add the character wrapped in ' to the string, and at the end eval the string to an array. Commented Dec 24, 2018 at 19:00
  • @JackBashford I'm not entirely certain I understand what you're describing. But if it isn't a multidimensional array of numbers, than no. Commented Dec 24, 2018 at 19:07
  • @Countingstuff If you can make that solution, I'd be interested in seeing it. Commented Dec 24, 2018 at 19:07
  • Are you actually using letters like "a","b","c", etc or are you just using those as examples? Otherwise, how do we determine the progression? Commented Dec 24, 2018 at 19:08

3 Answers 3

4

You could take a level variable and a levels array for pushing unknown elements.

var input = ['a', 'b', 'b', 'b', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'a', 'a', 'b', 'b'],
    levels = [[]],
    level = 0,
    result;

input.forEach(v => {
    var l = level;
    do {
        if (levels[l][0] === v) {
            level = l;
            levels[level].push(v);
            return;
        }
    } while (l--)
    levels[level].push(levels[level + 1] = [v]);
    level++;
});

result = levels[0][0];

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Sign up to request clarification or add additional context in comments.

3 Comments

Haha much better than my dumb eval thing :D.
Every time I come back to this answer it has been changed a little bit.
@bronkula, i changed the structure of the inner loop, which now loops from the level to zero. the loop is now much more simpler than before.
3

The dumb eval solution I had in mind, if it's what you wanted it can be made neat...

function toMulti(arr) {
    let str = "[";
    let level = 1;
    const charLevels = { a: 1, b: 2, c: 3 };
    arr.forEach(char => {
        const charLevel = charLevels[char];
        if (level < charLevel) {
            for (let i = 0; i < charLevel - level; i++) {
                str += "[";
            }
        }
        if (level > charLevel) {
            for (let i = 0; i < level - charLevel; i++) {
                str += "],";
            }
        }
        level = charLevel;
        str += `'${char}',`;
    });
    for (let i = 0; i < level; i++) {
        str += "]";
    }
    return eval(str);
}

Comments

2

Alternative version, using JSON building/parsing:

const input = ['a', 'b', 'b', 'b', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'a', 'a', 'b', 'b'];

const result = JSON.parse(Object.entries(input).reduce((json, [key, val]) => {
  const jsonVal = JSON.stringify(val);
  const diff = key > 0 ? val.charCodeAt(0) - input[key - 1].charCodeAt(0) : 0;
  if (diff > 0) {
    json += ',['.repeat(diff) + jsonVal;
  } else if (diff < 0) {
    json += ']'.repeat(-diff) + ',' + jsonVal;
  } else {
    json += (key > 0 ? ',' : '') + jsonVal;
  }
  return json;
}, '[') + ']'.repeat(input.slice(-1)[0].charCodeAt(0) - input[0].charCodeAt(0) + 1));

console.log(result);

This basically builds a JSON string using Array.reduce on the input array, adding each item and comparing key codes to include the right amount of opening/closing brackets in the process.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.