arunmmanoharan
arunmmanoharan

Reputation: 2675

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.

Upvotes: 3

Views: 111

Answers (6)

Tomas
Tomas

Reputation: 3436

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)

Upvotes: 0

ggorlen
ggorlen

Reputation: 57096

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);

Upvotes: 4

trincot
trincot

Reputation: 350477

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);

Upvotes: 1

Jonas Wilms
Jonas Wilms

Reputation: 138367

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]), });
  }
}

Upvotes: 0

Patryk Cieszkowski
Patryk Cieszkowski

Reputation: 751

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] ]
            }
          ])
      ]
    }, [])
    

Upvotes: 1

Nina Scholz
Nina Scholz

Reputation: 386650

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>

Upvotes: 2

Related Questions