Convert array of objects to one Object using ramda.js

Viewed 4205

I have an array:

var a = [
    {id: 1, val: 'a'},
    {id: 2, val: 'b'},
    {id: 3, val: 'c'},
    {id: 4, val: 'd'},
]

And I want to get transform it to:

var b = {
    1: 'a',
    2: 'b',
    3: 'c',
    4: 'd',
}

Actually I'm using pure js:

var b = a.reduce(
    (ac, pr) => ({
      ...ac,
      [pr.id]: pr.val,
    }),
    {}
  );

But maybe Ramda.js have something special for that purpose?

10 Answers

You are looking for Ramda's .mergeAll() method:

var b = R.mergeAll(a.map(function(o) {
  return {
    [o.id]: o.val
  }
}));

The .map()call will return the custom object from each item, taking only the values, then .mergeAll() will merge the array into one object.

mergeAll Documentation:

Merges a list of objects together into one object.

Demo:

var a = [{
    id: 1,
    val: 'a'
  },
  {
    id: 2,
    val: 'b'
  },
  {
    id: 3,
    val: 'c'
  },
  {
    id: 4,
    val: 'd'
  },
];


var b = R.mergeAll(a.map(function(o) {
  return {
    [o.id]: o.val
  }
}));
console.log(b);
<script src="https://cdn.jsdelivr.net/ramda/0.18.0/ramda.min.js"></script>

If anyone still passes by here, it does indeed:

R.indexBy(R.prop('id'), someArray);

See indexBy in Ramda's documentation

EDIT: Bennet is correct. If we want val as the only value per key, we can "pluck" it out after:

const createValDict = R.pipe(
  R.indexBy(R.prop('id')),
  R.pluck('val')
)

const valDict = createValDict(myArr)

Pluck works on objects too

var a = [
    {id: 1, val: 'a'},
    {id: 2, val: 'b'},
    {id: 3, val: 'c'},
    {id: 4, val: 'd'},
]

var result = {};
for (var i=0; i<a.length; i++) {
  result[a[i].id] = a[i].val;
}

console.log(result);

If you wanted something point-free, you could write:

const combine = compose(mergeAll, map(lift(objOf)(prop('id'), prop('val'))))

const {compose, mergeAll, map, lift, objOf, prop} = R;

const combine = compose(mergeAll, map(lift(objOf)(prop('id'), prop('val'))))

var a = [{id:1, val:'a'}, {id:2, val:'b'}, {id:3, val:'c'}, {id:4, val:'d'}]
console.log(combine(a));
<script src="https://cdn.jsdelivr.net/ramda/0.18.0/ramda.min.js"></script>

Here it works like a charm :

var a = [
    {id: 1, val: 'a'},
    {id: 2, val: 'b'},
    {id: 3, val: 'c'},
    {id: 4, val: 'd'},
];
// var b = R.fromPairs( a.map(Object.values) );
// Perhaps this is the more general and order independent way:
var b = R.fromPairs(a.map( ({id,val})=>[id,val] ));
console.log( b );
<script src="//cdn.jsdelivr.net/npm/ramda@latest/dist/ramda.min.js"></script>

This might be the simplest way:

pipe(map(props(['id', 'val'])), fromPairs)(a)

@spflow's answer is simpler but not guaranteed to work on all platforms. Ramda code golf is always fun!

const { fromPairs, map, pipe, props } = R

const a = [
    {id: 1, val: 'a'},
    {id: 2, val: 'b'},
    {id: 3, val: 'c'},
    {id: 4, val: 'd'},
]

const result = pipe(map(props(['id', 'val'])), fromPairs)(a)

console.log(result)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.min.js"></script>

Yet one approach:

const { indexBy, prop, pipe, pluck } = R
const a = [
    {id: 1, val: 'a'},
    {id: 2, val: 'b'},
    {id: 3, val: 'c'},
    {id: 4, val: 'd'},
]
const result = pipe(indexBy(prop('id')), pluck('val'))(a)
console.log(result)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.min.js"></script>

Simplest, point-free:

compose(fromPairs, map(values))(a)

const { compose, fromPairs, map, values } = R

const a = [
    {id: 1, val: 'a'},
    {id: 2, val: 'b'},
    {id: 3, val: 'c'},
    {id: 4, val: 'd'},
]

const result = compose(fromPairs, map(values))(a)

console.log(result)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

Related