1

I'm trying to build a list of all the unique levels in a multidimensional array of objects.

Assuming this data...

let levels = [
  ["P", "B", "L"],
  ["A", "B", "L3"],
  ["A", "B", "L3"],
  ["P", "B", "M"],
  ["P", "C", "L"],
  ["A", "C", "L3"]
];

I need to end up with an array structure like this:

const result = [
  [ 1, 'P', 11, 'P.B', 111, 'P.B.L' ],
  [ 1, 'P', 11, 'P.B', 112, 'P.B.M' ],
  [ 1, 'P', 12, 'P.C', 121, 'P.C.L' ],
  [ 2, 'A', 21, 'A.B', 211, 'A.B.L3' ],
  [ 2, 'A', 22, 'A.C', 221, 'A.C.L3' ]
];

Note:

Where each entry is an array of a unique level.

Level ids: 
1 => level 1 
11 => level 1 and its sub level
111 => level 1, its sub level and sub level's level

On each new level 1 the id will increment as follows for other sub-levels and sub level's level:
2 => new level 1 
21 => new level 1 and its new sub-level
211 => new level 1, its new sub-level and new sub level's level

I'm having real trouble calculating the level ids for each unique pair. So far I have tried to return the unique pairs only as below:

function updateLevels(levels) {
  const { result } = levels.reduce(
    (acc, crr) => {
      const l1Key = crr[0];
      const l2Key = `${l1Key}.${crr[1]}`;
      const l3Key = `${l2Key}.${crr[2]}`;

      if (!acc.checkMap[l3Key]) {
        acc.checkMap[l3Key] = true;
        acc.result.push([l1Key, l2Key, l3Key]);
      }

      return acc;
    },
    {
      checkMap: {},
      result: [],
    }
  );
  return result;
}

const result = 
[
  [ 'P', 'P.B', 'P.B.L' ],
  [ 'A', 'A.B', 'A.B.L3' ],
  [ 'P', 'P.B', 'P.B.M' ],
  [ 'P', 'P.C', 'P.C.L' ],
  [ 'A', 'A.C', 'A.C.L3' ]
]

1 Answer 1

1

Basically this solution needs two steps:

  1. Get an array with numbers and connected strings.

    You could take an object for keeping the level information and check if the actual data set exists with a flag add for pushing a new array to the result set.

  2. Sort the result by taking odd indices of the array.

const
    getUnique = array => {
        const levels = { _: 0, data: [] };
        
        return array
            .reduce((r, a) => {
                let add = false;
                const
                    temp = [],
                    final = a.reduce((l, v, i, a) => {
                        if (!l[v]) {
                            l[v] = {
                                _: 0,
                                data: [(l.data[0] || 0) * 10 + ++l._, (l.data[1] || '' ) + (l.data[1] ? '.' : '') + v]
                            };
                            add = true;
                        }
                        temp.push(...l[v].data);
                        return l[v];
                    }, levels);

                if (add) r.push(temp);

                return r;
            }, [])
            .sort((a, b) => {
                let i = 0, r = 0;
                while (i < a.length && !r) {
                    r = a[i] - b[i];
                    i += 2;
                }
                return r;
            });
    },
    levels = [["P", "B", "L"], ["A", "B", "L3"], ["A", "B", "L3"], ["P", "B", "M"], ["P", "C", "L"], ["A", "C", "L3"]],
    result = getUnique(levels);

result.forEach(a => console.log(...a));

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

4 Comments

Hi stackoverflow.com/users/1447675/nina-scholz, Thanks a lot for the solution. Seemed really feasible.
Hi stackoverflow.com/users/1447675/nina-scholz, I was trying to refactor the existing logic to be reused so that I can add/update only those levels which weren't added from the 1st dump/iteration. In the 2nd dump, I'm fetching the results from the DB first(array of objects) and then creating a map of it to maintain the hierarchy and compare the results from the 2nd dump which aren't in DB. But sadly I'm unable to calculate the ids of the levels correctly. Could you please help me?
@V_S, @Nina Scholz would be enough to address me.
@V_S, does this answer works for the question? if yes, accept it and ask a new question with the additional problem along with your try. if no, what goes wrong?

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.