yadav_vi
yadav_vi

Reputation: 1297

Using spread element to merge values in reduce of a javascript array

I have an array - types - which looks something like this -

[
  {"id": 1, "name": "Payment"},
  {"id": 2, "name": "Debit"},
  {"id": 3, "name": "Credit"},
  {"id": 4, "name": "Transaction"}
]

I want to transform the array into another array which looks like this -

[
  {"Payment": 1},
  {"Debit": 2},
  {"Credit": 3},
  {"Transaction": 4}
]

When I do the following, the first entry is always missing -

const typeArray = types === null || types.length === 0 ? [] :
    types.map((type) => {
        const id = type.id;
        const name = type.name;
        return {[name]: id};
    })
        .reduce((prev, curr) => [...prev, curr]);

I always get the output something like this -

[
  {"Debit": 2},
  {"Credit": 3},
  {"Transaction": 4}
]

When I instead use -

    .reduce((prev, curr) => [prev, curr]);

I get a nested array, but all the elements are present. The array looks like so -

[
   [
      [
        {"Payment":1},
        {"Debit":2}
      ],
      {"Credit":3}
   ],
   {"Transaction":4}
]

How do I do this. Is there something like flatMap() from RxJS where I can merge all the arrays into a single array?

Upvotes: 0

Views: 342

Answers (7)

Nina Scholz
Nina Scholz

Reputation: 386680

You could take a combination with Array#map instead of Array#reduce, because the accumulator is always the same and map fits better for getting an array with a value for each element, destructuring assignment for the properties and computed property names for the key of a new object.

var data = [{ id: 1, name: "Payment" }, { id: 2, name: "Debit" }, { id: 3, name: "Credit" }, { id: 4, name: "Transaction" }],
    result = data.map(({ id, name }) => ({ [name]: id }));

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

Upvotes: 1

Zahidul Islam
Zahidul Islam

Reputation: 125

One-liner reduce

const types = [
  {"id": 1, "name": "Payment"},
  {"id": 2, "name": "Debit"},
  {"id": 3, "name": "Credit"},
  {"id": 4, "name": "Transaction"}
]


const typeArrayReduce = types.reduce((acc, type) => acc.concat({[type.name]:type.id}), []);

console.log(typeArrayReduce);

Upvotes: -1

cнŝdk
cнŝdk

Reputation: 32145

Well you don't need the .reduce() call, because Array.prototype.reduce() applies a function against an accumulator and each element in the array (from left to right) to reduce it to a single value.

While Array.prototype.map() creates a new array with the results of calling a provided function on every element in the calling array, and that's exactly what you need here.

This is how should be your code:

const typeArray = types === null || types.length === 0 ? [] :
  types.map((type) => {
    const id = type.id;
    const name = type.name;
    return {
      [name]: id
    };
});

Demo:

var types = [
  {"id": 1, "name": "Payment"},
  {"id": 2, "name": "Debit"},
  {"id": 3, "name": "Credit"},
  {"id": 4, "name": "Transaction"}
];

const typeArray = types === null || types.length === 0 ? [] :
  types.map((type) => {
    const id = type.id;
    const name = type.name;
    return {
      [name]: id
    };
});
    
    console.log(typeArray);

Upvotes: 1

Suren Srapyan
Suren Srapyan

Reputation: 68665

Why you need to use reduce? It gets your desired result without it. Just work with Array#map.

const types = [
  {"id": 1, "name": "Payment"},
  {"id": 2, "name": "Debit"},
  {"id": 3, "name": "Credit"},
  {"id": 4, "name": "Transaction"}
]

const typeArrayMap = types.map((type) => ({ [type.name]: type.id }));
        
console.log(typeArrayMap);

const typeArrayReduce = types.reduce( (array,type)=>{
    array.push({[type.name]:type.id});
    return array;
}, []);

console.log(typeArrayReduce);

Using Array#reduce for aggregate purposes

const people = [
  {name: 'A', age: 7},
  {name: 'B', age: 8},
  {name: 'C', age: 9},
  {name: 'D', age: 10},
];

const sumOfAges = people.reduce( (total, person) => total + person.age, 0 );
console.log(sumOfAges);

Upvotes: 1

Mihai Alexandru-Ionut
Mihai Alexandru-Ionut

Reputation: 48407

You should use map method which accepts as parameter a callback function in order to obtain a cleaner solution.

The map() method creates a new array with the results of calling a provided function on every element in the calling array.

let array=[
  {"id": 1, "name": "Payment"},
  {"id": 2, "name": "Debit"},
  {"id": 3, "name": "Credit"},
  {"id": 4, "name": "Transaction"}
]
array=array.map(function(item){
  return {[item.name]:item.id};
});
console.log(array);

or using arrow functions:

array=array.map(item=> {[item.name]:item.id});

Also, you can use reduce function in this way:

let array=[
      {"id": 1, "name": "Payment"},
      {"id": 2, "name": "Debit"},
      {"id": 3, "name": "Credit"},
      {"id": 4, "name": "Transaction"}
    ]
array=array.reduce((arr,item)=>{
    arr.push({[item.name]:item.id});
    return arr;
},[]);
console.log(array);

Upvotes: 3

Tamas Hegedus
Tamas Hegedus

Reputation: 29926

Your code throws an exception in Chrome, see:

console.log([1,2,3].reduce((a,b)=>[...a,b]));

The reason: .reduce has two arguments. The second one is the initial value of prev:

console.log([1,2,3].reduce((a,b)=>[...a,b], []));

But as others already pointed out: you don't need reduce here. Your sequence is already an array, and even if it wasn't there would be better ways to convert it to an array.

Upvotes: 0

Ivan Minakov
Ivan Minakov

Reputation: 1442

Use map like this:

let data = [
  {"id": 1, "name": "Payment"},
  {"id": 2, "name": "Debit"},
  {"id": 3, "name": "Credit"},
  {"id": 4, "name": "Transaction"}
];

let result = data.map((elem) => ({ [elem.name]: elem.id }));

console.log(result);

Upvotes: 1

Related Questions