7

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?

3
  • ramdajs.com Commented Nov 27, 2017 at 8:31
  • 2
    Note that id is coerced to String during the transformation. Type coercion can lead to subtle bugs. Instead of using Object's as dictionaries, you should use a proper dictionary: Map, where keys can actually be Numbers. Commented Nov 27, 2017 at 9:17
  • If you choose to go with a Map rather than a plain object, you can instantiate it using var b = new Map(a.map(({id, val}) => [id, val])) Commented Nov 27, 2017 at 16:25

9 Answers 9

7

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>

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

5 Comments

where does ramda knows, which property is the key and which the value?
@NinaScholz source
it looks like the equivalent of Object.assign, but the rest is missing for the problem.
@Nick Yes I updated the answer, it just needs mapping the itesm before calling .mergeAll().
@NinaScholz Well pointed out, thanks. I missed the fact that there are two properties.
6

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

1 Comment

This is good but doesn't give exactly the result the OP wanted...
3

Get the ordered values from each object by mapping with R.props, and use R.fromPairs to create an object:

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

var result = R.compose(R.fromPairs, R.map(R.props(['id', 'val'])));

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

Comments

2

With plain Javascript, you could use a combination with Object.assign, spread syntax ..., Array#map, destructuring assignment and short hand properties.

var a = [{ id: 1, val: 'a' }, { id: 2, val: 'b' }, { id: 3, val: 'c' }, { id: 4, val: 'd' }],
    result = Object.assign(...a.map(({ id, val }) => ({ [id]: val })));

console.log(result);

Comments

0

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

Comments

0

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>

Comments

0

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>

2 Comments

Note that this solution relies on the order in which the objects' properties are defined. It will break if, for example, you add { val: 'e', id: 5 }.
@user3297291 Yes you're right it's case specific , so I've edited the code.
0

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>

Comments

0

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>

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.