Simpler
Simpler

Reputation: 1369

Consolidate / Manipulate array of objects

I have an array of objects like the following:

[{
  animal: "cat",
  dateString: "2017-01-03"
},{
  animal: "dog",
  dateString: "2017-02-05"
},{
  animal: "cat",
  dateString: "2017-03-04"
}]

and I'd like to create a new array that looks like:

[{
  animal: "cat",
  values: [
    "2017-01-03",
    "2017-03-04"
  ]
},{
  animal: "dog",
  values: [
    "2017-02-05"
  ]
}]

How can I consolidate the individual object properties into an array of values?

Upvotes: 0

Views: 118

Answers (7)

Nir Alfasi
Nir Alfasi

Reputation: 53525

We can simply iterate the array and build a result by mapping each animal to and object that contains its properties, e.g. {'cat': {'animal': 'cat', 'values': ["2017-01-03"]}}. When we're done, we'll extract only the values:

const arr = [{
  animal: "cat",
  dateString: "2017-01-03"
},{
  animal: "dog",
  dateString: "2017-02-05"
},{
  animal: "cat",
  dateString: "2017-03-04"
}]

let res=  {}
arr.forEach(obj => {
  if (res[obj.animal]) {
    res[obj.animal].values.push(obj.dateString)
  } else {
    res[obj.animal] = {animal: obj.animal, values: [obj.dateString]}
  }
})

res = Object.values(res)
console.log(res)
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 0

Carl Edwards
Carl Edwards

Reputation: 14434

Here you first create a new, empty array and a for-loop. From there you either create a brand new object with of the animal type or just push the dateString value of the other if it does:

const animals = [{
  animal: "cat",
  dateString: "2017-01-03"
}, {
  animal: "dog",
  dateString: "2017-02-05"
}, {
  animal: "cat",
  dateString: "2017-03-04"
}];

const combined = [];

for (let i = 0; i < animals.length; i++) {
  const { animal, dateString } = animals[i];
  
  const animalIndex = combined.findIndex(obj => {
    return obj['animal'] === animal;
  });
  
  if (animalIndex === -1) {
    combined.push({ animal, values: [dateString] });
  } else {
    combined[animalIndex]['values'].push(dateString);
  }
}

console.log(combined);

Upvotes: 0

Varun
Varun

Reputation: 1946

Since you have not tagged only JS, try this (Vanilla JS)

    var x = [{
        animal: "cat",
        dateString: "2017-01-03"
     },{
        animal: "dog",
        dateString: "2017-02-05"
     },{
        animal: "cat",
        dateString: "2017-03-04"
    }];

    let usedKeys = [];
    let finalArray = [];

    for(var z = 0; z < x.length ; z++)
    {
       if(usedKeys.indexOf(x[z]['animal']) == '-1')
       {
           usedKeys.push(x[z]['animal']);
           finalArray.push({'animal':x[z]['animal'] , 'values':[x[z]['dateString']]});
       }
       else
       {
           let targetIndex = usedKeys.indexOf(x[z]['animal']);
           finalArray[targetIndex]['values'].push(x[z]['dateString']);
       }
    }

console.log(finalArray);

Upvotes: 0

Hassan Imam
Hassan Imam

Reputation: 22524

You can use array#reduce to store your object in a new object where values will be grouped on based on animal name. Then, use Object.values to get the result.

var data = [{ animal: "cat", dateString: "2017-01-03" },{ animal: "dog", dateString: "2017-02-05" },{ animal: "cat", dateString: "2017-03-04" }];

var result = data.reduce((o, {animal, dateString}) => {
  o[animal] ? o[animal].values.push(dateString) : o[animal] = {animal, values: [dateString]}
  return o;
},{});

var output = Object.values(result);
console.log(output);

Upvotes: 0

mr.incredible
mr.incredible

Reputation: 4185

You could use forEach method to double sort your array.

var arr = [{
  animal: "cat",
  dateString: "2017-01-03"
},{
  animal: "dog",
  dateString: "2017-02-05"
},{
  animal: "cat",
  dateString: "2017-03-04"
}];

var sorted = [];

arr.forEach(function callback(arrVal, index1, array1) {
   sorted.forEach(function callback(sortVal, index2, array2) {
      if (arrVal == sortVal) {
         sorted[index2].values.push(arrVal.dateString);
      } else {
         sorted.push({animal: arr[index1].animal, values: [arr[index1].dateString]});
      }
   });
});

Hope it will help.

Upvotes: 0

simbathesailor
simbathesailor

Reputation: 3687

var data=[{
  animal: "cat",
  dateString: "2017-01-03"
},{
  animal: "dog",
  dateString: "2017-02-05"
},{
  animal: "cat",
  dateString: "2017-03-04"
}]

var ans = data.reduce(function(accumulator, element) {
var elementInAccumulator = accumulator[element.animal]
if(elementInAccumulator) {
  if(Array.isArray(elementInAccumulator.values)) {
    elementInAccumulator.values.push(element.dateString)
  }
  else {
  var arr=[]
  
  arr.push(elementInAccumulator.dateString)
  arr.push(element.dateString)
  elementInAccumulator.values= arr
  delete(elementInAccumulator.dateString)
  }
}
else {
  accumulator[element.animal] = element
}
return accumulator
}, {})
console.log(Object.keys(ans).map(function(element) {
  return ans[element]
}))

Upvotes: 0

Rick Lee
Rick Lee

Reputation: 763

Without lodash/ramda u can do

const a = [
  {
    animal: 'cat',
    dateString: '2017-01-03'
  }, {
    animal: 'dog',
    dateString: '2017-02-05'
  }, {
    animal: 'cat',
    dateString: '2017-03-04'
  }
]

const b = Object.values(a.reduce((a, b) => {
  if (a[b.animal]) {
    a[b.animal].values.push(b.dateString)
  } else {
    a[b.animal] = {animal: b.animal, values: [b.dateString]}
  }
  return a
}, {}))

Upvotes: 2

Related Questions