简体   繁体   中英

Convert array of arrays to array of objects grouped together

I have an array of arrays. How do I convert them to an array of objects grouped together?

 var abc = [ ['apple', 'fruit'], ['banana', 'fruit'], ['grapes', 'fruit'], ['red', 'color'], ['blue', 'color'], ['black', 'color'] ] abc = abc.map(function(item) { return { value: item[0], color: item[1] } }) colors = abc.filter(function(item) { return item.color === 'color' }) fruits = abc.filter(function(item) { return item.color === 'fruit' }) var result = [{ group: 'color', value: colors.map(function(item) { return item.value }) }, { group: 'fruit', value: fruits.map(function(item) { return item.value }) }] console.log(result) 

My expected output is:

var abc = [
{
    group: 'color',
    value: ['red', 'blue', 'black']
},
{
    group: 'fruit',
    value: ['apple', 'banana', 'grapes']
}]

Is there an easier way to achieve this?

I can use lodash too. Please advise.

Here's an approach using reduce and map . reduce performs an aggregation by group mapped to an array of values. Object.entries() and map transform this grouping into the desired format as an array of objects.

 var abc = [ ['apple', 'fruit'], ['banana', 'fruit'], ['grapes', 'fruit'], ['red', 'color'], ['blue', 'color'], ['black', 'color'] ]; const result = Object.entries( abc.reduce((a, e) => { if (!(e[1] in a)) { a[e[1]] = []; } a[e[1]].push(e[0]); return a; }, {}) ).map(e => ({group: e[0], value: e[1]})) ; console.log(result); 

You could group with lodash by the index and map the values of the other index.

 var data = [['apple', 'fruit'], ['banana', 'fruit'], ['grapes', 'fruit'], ['red', 'color'], ['blue', 'color'], ['black', 'color']], result = _(data) .groupBy(1) .map((array, group) => ({ group, value: _.map(array, 0) })) .sortBy('group') .value(); console.log(result); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script> 

Here's a method I've described in a comment to your question:

  1. you loop through all elements, and create a blank array
  2. Inside of your newly created array, you find object matching group value
  3. If found, you extend the element
  4. If not found, you create it

     abc.reduce((arr, input) => { const index = arr.findIndex(i => i.group === input[0]) return [ ...(index > -1 ? [ ...arr.slice(0, index), { group: input[0], value: [ ...arr[index].value, input[1] ] }, ...arr.slice(index + 1) ] : [ ...arr, { group: input[0], value: [ input[1] ] } ]) ] }, []) 

Here is way to do it with an ES6 Map as intermediate data structure:

 var abc = [['apple', 'fruit'],['banana', 'fruit'],['grapes', 'fruit'],['red', 'color'],['blue', 'color'],['black', 'color']]; const groups = new Map(abc.map(a =>[a[1], []])); abc.forEach(a => groups.get(a[1]).push(a[0])); const result = Array.from(groups, ([group, values]) => ({group, values})); console.log(result); 

You could build up a hashtavle to find duplicate descriptors:

 const result = [], hash = {};

 for(const [value, group] of abc) {
  if(hash[group]) {
   hash[group].push(value);
  } else {
   result.push({ group, value: (hash[group] = [value]), });
  }
}

Approach with single reduce

var abc = [
  ['apple', 'fruit'],
  ['banana', 'fruit'],
  ['grapes', 'fruit'],
  ['red', 'color'],
  ['blue', 'color'],
  ['black', 'color']
]

var r = abc.reduce((prev, curr) => {
  if(prev.findIndex(p => p.group === curr[1]) === -1) {
    prev = prev.concat({group: curr[1], value: []})
  }
  let idx = prev.findIndex(p => p.group === curr[1])
  prev[idx].value.push( curr[0] )
  return prev;
}, [])

console.log(r)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM