Reputation: 569
Let's say I have a js object such as this
{
a: 5,
b: 1,
c: 3
}
What I would like to do using Underscore is generate an array which would resemble the following;
["a","a","a","a","a","b","c","c","c"]
I can achieve what I want with the following code
var i = {
a: 5,
b: 1,
c: 3
};
unpack = function (i, item) {
var items = [];
_.range(0, i).forEach(function (i) {
items.push(item)
})
return items;
}
console.log(_.flatten(_.map(i, unpack)));
http://jsfiddle.net/VCFZx/ but it doesnt seem the tidiest way of doing it?
Upvotes: 3
Views: 135
Reputation: 23472
In ECMA5 you could do it like this
Javascript
function createFilledArray(obj) {
return Object.keys(obj).reduce(function(acc, key) {
var repeat = obj[key],
count;
for(count = 0; count < repeat; count += 1) {
acc.push(key);
}
return acc;
}, []);
}
var a = {
'a': 5,
'b': 1,
'c': 3
};
console.log(createFilledArray(a));
On jsFiddle
Which in terms of underscore
would look like this
Javascript
function createFilledArray(obj) {
return _.reduce(_.keys(obj), function(acc, key) {
var repeat = obj[key],
count;
for(count = 0; count < repeat; count += 1) {
acc.push(key);
}
return acc;
}, []);
}
On jsFiddle
Which if you wanted to go further and replace the for
Javascript
function createFilledArray(obj) {
return _.reduce(_.keys(obj), function(acc, key) {
_.times(obj[key], function() {
acc.push(key);
});
return acc;
}, []);
}
On jsFiddle
And now for a little interest factor, lets have a look at the performances of the above 3 functions as we introduce more of Underscores methods, and we'll also compare them against the accepted solution by @mrhobo
Here is the jsPerf
Something else that none of these take into account, and it is unclear from your question, is whether alphabetical order is a must. If it is then a sort
will need to be thrown into the mix, as none of these guarantee the ordering.
Finally, in ES3 as mentioned in the comments.
Javascript
function createFilledArray(obj) {
var acc = [],
key,
repeat,
count;
for (key in obj) {
if (obj.hasOwnProperty(key)) {
for (count = 0, repeat = obj[key]; count < repeat; count += 1) {
acc.push(key);
}
}
}
return acc;
}
On jsFiddle
I have added the ES3 method to the jsPerf also.
And if you want to chain the result with other Underscore methods.
_.chain(createFilledArray(a)).forEach(function(element) {
console.log(element);
});
Upvotes: 2
Reputation: 19987
How about this:
var obj =
{
a :5,
b : 1,
c : 3
};
console.log(
_.flatten(_.map(_.keys(obj), function (key) {
return _.times(obj[key], function() { return key; });
}))
);
Note that this solution is purely functional.
Here is a nicely chained version:
_.chain(_.keys(obj))
.map(function (key) {
return _.times(obj[key], function() { return key; }); })
.flatten()
.value()
Upvotes: 2