Search code examples
javascriptarraysobjectecmascript-6ecmascript-5

Efficiently converting 2D array to an object erasing duplicates in JavaScript


For example if one has the following 2D array (arranged to be [[key, value], [key, value]]):

var input_array = [
  ["one", "stuff"], 
  ["two", "things"], 
  ["two", "more things"], 
  ["three", "stuff"], 
  ["one", "something"], 
  ["one", "stuff"], 
  ["two", "more things"], 
  ["three", "more stuff"]
]

What is a minimal and efficient way using what ES5/6 has to offer (as oppose to for loops with counters) to create an output object with array values that get rid of the duplicate pairs and sort the array values in alphabetical order:

var output_obj = {
  "one": ["something", "stuff"],
  "two": ["more things", "things"],
  "three": ["more stuff", "stuff"]
}

Solution

  • This can be as concise as a single line reduce using logical nullish assignment (??=), adding elements to a Set() to handle duplicates, and then iterating the resulting Object.keys() to convert the Sets to arrays using spread syntax while also sorting them.

    const input = [["one", "stuff"], ["two", "things"], ["two", "more things"], ["three", "stuff"], ["one", "something"], ["one", "stuff"], ["two", "more things"], ["three", "more stuff"]];
    
    const
      output = input.reduce((a, [k, v]) => ((a[k] ??= new Set()).add(v), a), {});
    Object.keys(output).forEach(k => output[k] = [...output[k]].sort());
    
    console.log(output)

    or if you need to avoid logical nullish assignment for compatibility...

    const input = [["one", "stuff"], ["two", "things"], ["two", "more things"], ["three", "stuff"], ["one", "something"], ["one", "stuff"], ["two", "more things"], ["three", "more stuff"]];
    
    const
      output = input.reduce((a, [k, v]) => ((a[k] = a[k] || new Set()).add(v), a), {});
    Object.keys(output).forEach(k => output[k] = [...output[k]].sort());
    
    console.log(output)