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?

n06rin
  • 173
  • 2
  • 9
  • http://ramdajs.com/ – SPlatten Nov 27 '17 at 08: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 `Number`s. –  Nov 27 '17 at 09: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]))` – user3297291 Nov 27 '17 at 16:25

10 Answers10

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>
cнŝdk
  • 31,391
  • 7
  • 56
  • 78
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

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>
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
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);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
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);
vicky patel
  • 699
  • 2
  • 8
  • 14
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>
Scott Sauyet
  • 49,207
  • 4
  • 49
  • 103
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>
nullqube
  • 2,959
  • 19
  • 18
  • 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 Nov 30 '17 at 18:54
  • @user3297291 Yes you're right it's case specific , so I've edited the code. – nullqube Dec 01 '17 at 07:20
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>
Bennett McElwee
  • 24,740
  • 6
  • 54
  • 63
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>
v.bortsov
  • 1
  • 1
-1

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>
spflow
  • 1,010
  • 7
  • 12
  • 1
    Since the ordering of `values` is not guaranteed across different JS platforms, you might end up with the keys and values reversed, like `{"a": "1", ` etc. – Bennett McElwee Mar 31 '21 at 04:18