15

Is there an easy/clean way using Underscore to turn this

[ { id: 'medium', votes: 7 },
  { id: 'low',    votes: 9 },
  { id: 'high',   votes: 5 } ]

Into

 { 'low'    : 9,
   'medium' : 7,
   'high'   : 5 }

8 Answers 8

43

You might consider _.indexBy(...)

var data = [{
    id: 1,
    name: 'Jon Doe',
    birthdate: '1/1/1991',
    height: '5 11'
}, {
    id: 2,
    name: 'Jane Smith',
    birthdate: '1/1/1981',
    height: '5 6'
}, {
    id: 3,
    name: 'Rockin Joe',
    birthdate: '4/4/1994',
    height: '6 1'
}, {
    id: 4,
    name: 'Jane Blane',
    birthdate: '1/1/1971',
    height: '5 9'
}, ];

var transformed = _.indexBy(data, 'id');

Here is a fiddle: https://jsfiddle.net/4vyLtcrf/3/

Update: In Lodash 4.0.1 the method _.indexBy has been renamed to _.keyBy

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

2 Comments

+1 for readability. Worth noting that the id property will still be present in the resulting objects, but that should be okay in most cases (and easy to post-exclude in others).
A similar solution for those looking to have each key in the final object as an array of items with that key (as opposed to a single item), there's also _.groupBy()
17
var data = [ { id: 'medium', votes: 7 },
  { id: 'low',    votes: 9 },
  { id: 'high',   votes: 5 } ];

You can do this with _.map, _.values and _.object, like this

console.log(_.object(_.map(data, _.values)));
# { medium: 7, low: 9, high: 5 }

Explanation

We use the map function to apply the values function (which gets all the values of a given object) over all the elements of data, which would give

# [ [ 'medium', 7 ], [ 'low', 9 ], [ 'high', 5 ] ]

Then we use object function to transform this into an object.

7 Comments

An interesting answer, but perhaps you could clarify what data is firstly, eg data = x;
I used Krasimir's answer, but you answered the question using underscore and there is more to learn for anyone interested in that sort of thing.
@dewd Please check the definition of data. There was a newline. I just removed it now.
How can you be sure that _.values({id: 'medium', votes: 7}) returns ['medium', 7] and not [7, 'medium']?
this solution is unreliable, relying on ordering of properties in your objects
|
8

Here is with vanilla js:

var result = {};
[ { id: 'medium', votes: 7 },
  { id: 'low',    votes: 9 },
  { id: 'high',   votes: 5 } ].forEach(function(obj) {
    result[obj.id] = obj.votes;
});
console.log(result);

Comments

2

simpler with me: each:

   var t = {};
   _.each(x, function(e){
     t[e.id] = e.votes;
   });
//--> {medium: 7, low: 9, high: 5}

Comments

1

The most powerfull method of underscore is reduce. You can do almost anything with it. And the bigger benefit is you iterate over the collection only ONCE!

var array = [ 
    { id: 'medium', votes: 7 },
    { id: 'low',    votes: 9 },
    { id: 'high',   votes: 5 } 
];
var object = _.reduce(array, function(_object, item) { 
    _object[item.id] = item.votes; 
    return _object; 
}, {});

After it runs, object will be:

{
  medium:7,
  low:9,
  high:5
}

3 Comments

It's an anti-pattern to dynamically add new properties to an object in JavaScript. richardartoul.github.io/jekyll/update/2015/04/26/…
Got it! That said @morio, what is your suggested solution?
Hm, you got me. Now I think about it, I don't know if there a way to avoid this. I guess libraries like Lodash are doing the same thing internally.
0

Use indexBy

_.indexBy([ 
   { id: 'medium', votes: 7 },
   { id: 'low',    votes: 9 },
   { id: 'high',   votes: 5 } 
 ], 'id');

Comments

0

I know this is an old post, but you could use _.reduce to do the transform in a clean way

var data = [
    { id: 'medium', votes: 7 },
    { id: 'low',    votes: 9 },
    { id: 'high',   votes: 5 }
]

var output = _.reduce(data, function(memo, entry) {
    memo[entry.id] = entry.votes;
    return memo;
}, {});

console.log(output);

Comments

0

You can do this with native JS Array.reduce

const myArray = [ { id: 'medium', votes: 7 },
{ id: 'low',    votes: 9 },
{ id: 'high',   votes: 5 } ]

const myObject = myArray.reduce((obj, item)=>{
  o[item.id] = item.votes
  return o
}, {})

for more details, take a look at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.