0

I would like to group the values of this array by its car key and then push the values common to that car into a values array.

I managed to do it with this but was wondering if there was an simpler way to do it with reduce.

const arr = [{
  car: 'audi',
  value: 'black'
}, {
  car: 'audi',
  value: 'expensive'
}, {
  car: 'fiat',
  value: 'red'
}, {
  car: 'fiat',
  value: 'cheap'
}]

// Simple array with unique car
const cars = Array.from(new Set(arr.map(({ car }) => car)))
// Array of objects with unique `car` and an empty `values` array for each
const result = cars.map((car) => ({ car, values: [] }))

// Push to values array the `value` for each car
arr.map((obj) => {
  result.map((res) => {
    if (obj.car === res.car) {
      res.values.push(obj.value)
    }
  })
})

console.log(result)
/*
[{
  car: 'audi',
  values: ['black', 'expensive']
}, {
  car: 'fiat',
  values: ['red', 'cheap']
}]
*/

3 Answers 3

2

Make an object indexed by the car name, then iterate over original array, pushing the value to the array on the object:

const arr = [{
  car: 'audi',
  value: 'black'
}, {
  car: 'audi',
  value: 'expensive'
}, {
  car: 'fiat',
  value: 'red'
}, {
  car: 'fiat',
  value: 'cheap'
}];

const carsByName = {};
for (const { car, value } of arr) {
  if (!carsByName[car]) carsByName[car] = { car, value: [] };
  carsByName[car].value.push(value);
}
console.log(Object.values(carsByName));

While this could be done with reduce, it's arguably not very semantically appropriate when the accumulator never changes (and is a bit noisy, syntactically):

const arr = [{
  car: 'audi',
  value: 'black'
}, {
  car: 'audi',
  value: 'expensive'
}, {
  car: 'fiat',
  value: 'red'
}, {
  car: 'fiat',
  value: 'cheap'
}];

const carsByName = arr.reduce((a, { car, value }) => {
  if (!a[car]) a[car] = { car, value: [] };
  a[car].value.push(value);
  return a;
}, {});
console.log(Object.values(carsByName));

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks, looks great, could I do [carsByName] instead of Object.values(carsByName)?
That would give you an array containing a single object, with that object being indexed by car name. If that data structure is what you want, go for it, but it's not what your expected output in the question was.
You are right, many thanks for the code works great
2

Just use reduce for it. Keep in acc the array of cars with keys car and values. And then map it. I mean:

const arr = [
  {
    car: "audi",
    value: "black",
  },
  {
    car: "audi",
    value: "expensive",
  },
  {
    car: "fiat",
    value: "red",
  },
  {
    car: "fiat",
    value: "cheap",
  },
];

const result = Object.entries(
  arr.reduce((acc, { car, value }) => {
    if (acc[car]) {
      return {
        ...acc,
        [car]: [...acc[car], value],
      };
    }

    return { ...acc, [car]: [value] };
  }, [])
).map(([car, values]) => ({ car, values }));

console.log(result);

Comments

1

You can use .reduce to group the items by car, and then, .map to create a list of objects having car and its values:

const arr = [{
  car: 'audi',
  value: 'black'
}, {
  car: 'audi',
  value: 'expensive'
}, {
  car: 'fiat',
  value: 'red'
}, {
  car: 'fiat',
  value: 'cheap'
}]

let result = arr.reduce((acc,item) => {
  const values = acc[item.car];
  acc[item.car] = values ? [...values, item.value] : [item.value];
  return acc;
}, {});

result = Object.entries(result).map(([car, values]) => ({car,values}));

console.log(result)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.