1

I am trying to reformat my list of objects by grouping a certain key pair in javascript.

Data Format

[{
    "sccode": "sccode1",
    "val": "1ADA"
}, {
    "sccode": "sccode2",
    "val": "1ADB"
}, {
    "sccode": "sccode1",
    "val": "1ADC"
}]

Expected Result

[{
        "scCode": "sccode1",
        "valCodes": ["1ADA", "1ADC"]
    }, 
{
        "scCode": "sccode2",
        "valCodes": ["1ADB"]
    }

]

I believe I could loop through the array and match my keys, but is there a quick way to reformat this without having to explicitly loop through? I've tried using a reduce function below, but it gives undefined errors with find, which i think has something to do with my formatting.

Tried (?) Code

 const resp = data.reduce((acc, ele) => {
          const ant = acc.find(x => x.sccode === ele.sccode);
        }, []);
Jack N
  • 175
  • 1
  • 10

4 Answers4

2

Would this do?

const src = [{"sccode":"sccode1","val":"1ADA"},{"sccode":"sccode2","val":"1ADB"},{"sccode":"sccode1","val":"1ADC"}],

    result = src.reduce((r,{sccode,val}) => {
      const match = r.find(({scCode}) => scCode == sccode)
      match ?
      match.valCodes.push(val) :
      r.push({scCode:sccode, valCodes: [val]})
      return r
    }, [])
    
console.log(result)
.as-console-wrapper{min-height:100%;}
Yevhen Horbunkov
  • 14,965
  • 3
  • 20
  • 42
1

Try the following, I use a map to store a partial state to improve performances preventing to search sccode in an array for every initial object.

let partial = [{
  "sccode": "sccode1",
  "val": "1ADA"
}, {
  "sccode": "sccode2",
  "val": "1ADB"
}, {
  "sccode": "sccode1",
  "val": "1ADC"
}].reduce((map, obj) => {
  if (!map[obj.sccode]) {
    map[obj.sccode] = [obj.val];
  } else {
    map[obj.sccode].push(obj.val);
  }
  return map;
}, {})

Object.keys(partial).map(sccode => ({
  sccode, valCodes: partial[sccode]
}));
TheGr8_Nik
  • 3,080
  • 4
  • 18
  • 33
  • Even though I agree that, in general, O(n) -time algorithms (your solution) are naturally faster than O(n²) (mine). But it is still questionable at which point (source array size and group key `sccode` variation) more optimal algorithm will outperform *heavier* (involving type switching and `Object.keys()` extraction) implementation. – Yevhen Horbunkov Mar 31 '20 at 20:03
  • Unfortunatelly, I couldn't benchmark that as your code fails with error even when copy pasted as is into the console. – Yevhen Horbunkov Mar 31 '20 at 20:04
  • @YevgenGorbunkov look at this https://stackoverflow.com/questions/17295056/array-vs-object-efficiency-in-javascript – TheGr8_Nik Mar 31 '20 at 21:06
  • as being said, I have no doubts that 2 passes over the array ***theoretically*** are faster than single pass with nested look ups (and I don't need to scroll the thread 10 miles long to get convinced). However, it depends on source data structure and typical size whether you will see the performance gain that outweighs *slow* `Object.keyss()` mapping and data types switching (not to mention greater code verbosity). If you would manage to post working code at the very beginning I would do my benchmarking and, furthermore, gladly upvoted your answer if it is really blazing fast. – Yevhen Horbunkov Mar 31 '20 at 21:34
  • @YevgenGorbunkov I agree with you, it depends on how much data has to be processed and how many different sccodes there are. Code is working, was missing the return in reduce function. – TheGr8_Nik Mar 31 '20 at 22:03
0

try loaddash/groupby

let groupByResult = groupBy(data, function (n) {
          return n.sccode
        });
Nonik
  • 645
  • 4
  • 11
0

Check this code:

    array.reduce(function(res, value){
        if(!res[value.sccode]) {
            res[value.sccode] = value; 
            res[value.sccode]['valCodes'] = []
            result.push(res[value.sccode]);
        }
        res[value.sccode]['valCodes'].push(value.val); 
        return res; 
    } ,{}); 

I tested here and it works fine!