Skip to content
Advertisement

JS: Nested Maps

I was trying to implement a [Wordle][1] assistant in JavaScript. I am new to JS, and I am sure the following is trivial, but maps are still confusing me. Suppose I have:

{
  'fight' => [ '02222', '02222', '02222', '02222', '20000' ],
  'eight' => [ '02222', '02222', '02222', '02222', '10000' ],
  'right' => [ '02222', '02222', '02222', '02222', '10000' ],
  'sight' => [ '02222', '02222', '02222', '02222', '10000' ],
  'night' => [ '02222', '02222', '02222', '02222', '10000' ],
  'ferns' => [ '20000', '01000', '00100', '00001', '00010' ]
}

How can I have the counts of unique items in the following format:

[{
    "fight": [1, 4],
    "eight": [1, 4],
    "right": [1, 4],
    "sight": [1, 4],
    "night": [1, 4],
    "ferns": [1, 1, 1, 1, 1]
}]

(Would I do better with a different data structure?)

(These are calculated values, so I have no idea what the keys of data are going to be, neither how many items each key will have.)

Advertisement

Answer

Edit

To remap your updated data is simpler in many ways. I’m assuming your syntax indicates that you are using a Map, and since a Map can not have duplicate keys you needn’t ‘group-by’ but simply iterate over the entries of the map transforming each values array by counting the non-zero characters in each string. Since you also want to remove duplicate counts ([1, 4] and not [1, 4, 4, 4, 4]) you can create an intermediate Set of each values array before spreading it back into an array and then mapping it to count characters.

const input = new Map([['fight', ['02222', '02222', '02222', '02222', '20000']], ['eight', ['02222', '02222', '02222', '02222', '10000']], ['right', ['02222', '02222', '02222', '02222', '10000']], ['sight', ['02222', '02222', '02222', '02222', '10000']], ['night', ['02222', '02222', '02222', '02222', '10000']], ['ferns', ['20000', '01000', '00100', '00001', '00010']]]);

// Map(6) {
//   'fight' => [ '02222', '02222', '02222', '02222', '20000' ],
//   'eight' => [ '02222', '02222', '02222', '02222', '10000' ],
//   'right' => [ '02222', '02222', '02222', '02222', '10000' ],
//   'sight' => [ '02222', '02222', '02222', '02222', '10000' ],
//   'night' => [ '02222', '02222', '02222', '02222', '10000' ],
//   'ferns' => [ '20000', '01000', '00100', '00001', '00010' ]
// }

const result = {};

for (const [key, values] of input.entries()) {
  result[key] = [...new Set(values)].map(s => s.match(/[^0]/g).length)
}

console.log(result)

I’m using a String.match() with a regex here to count non-zero digits in the string, but there are plenty of alternatives, here are two off the top of my head:

// String#replaceAll()
'02222'.replaceAll('0', '').length;

// String#split() + filter()
'02222'.split('').filter(c => c !== '0').length;

Original answer

Your data sample leaves a lot of questions both about what shape the input could be as well as what you would like the output to be. But regardless it seems that a fairly standard ‘group-by’ will work.

const data = [{ "fight": [{ "20000": 1, "02222": 4 }], "eight": [{ "10000": 1, "02222": 4 }], "right": [{ "20000": 1, "02222": 4 }], "sight": [{ "20000": 1, "02222": 4 }], "night": [{ "20000": 1, "02222": 4 }], "ferns": [{ "20000": 1, "01000": 1, "00100": 1, "00001": 1, "00010": 1 }] }];

const result = {};

for (const datum of data) {
  for (const [k, v] of Object.entries(datum)) {
    const values = v.flatMap(Object.values);
    (result[k] ??= [0]).push(...values);
    result[k][0] += values.length; // <-- This doesn't need to be stored, it is just the array.length (not including this element)
  }
}

console.log(result);

The above assumes that you might have duplicate keys, and flattens the result into a single object. If data will contain multiple objects and you want to maintain the grouped results within those bounds you’ll need to group per iteration. (The inner logic remains the same)

const data = [
  {
    "fight": [
      { "20000": 1, "02222": 4 },
      { "20000": 1, "01000": 1, "00100": 1, "00001": 1, "00010": 1 }
    ]
  },
  {
    "sight": [
      { "20000": 1, "02222": 4 }
    ],
    "night": [
      { "20000": 1, "02222": 4 },
      { "20000": 1, "02222": 4 }
    ]
  }
];

const result = [];

for (const datum of data) {
  const group = {}
  for (const [k, v] of Object.entries(datum)) {
    const values = v.flatMap(Object.values);
    (group[k] ??= [0]).push(...values);
    group[k][0] += values.length;
  }
  result.push(group)
}

console.log(result);
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement