1

I have an array of many unique strings and I'd like, without looping if at all possible, to create a map object from it where the key for each element is a unique string and the value is defaulted to some arbitrary setting.

Is there a way I can do this in one line without looping? I.e. I want to go from

var colours = [ "Red", "Orange", "Yellow", "Green", "Blue", "Indigo", "Violet" ];

to

var colourMap = {
    "Red":    VAL,
    "Orange": VAL,
    "Yellow": VAL,
    "Green":  VAL,
    "Blue":   VAL,
    "Indigo": VAL,
    "Violet": VAL
};
8
  • You mention in a comment below that you are looking to optimize this for performance since this code will be code repeatedly. First of all, can't you cache this in a variable in a higher scope? Unless the color list or VAL is going to be different every time there is no reason why you cannot. Second - are you sure performance is a problem? Most of the different techniques (for loop, reduce, forEach, underscore) have very similar performance and are unlikely to be your bottleneck. Profile before micro-optimizing! Commented Feb 3, 2014 at 15:39
  • @GeorgeMauer: Yes, good points which I will follow up. I suppose my underlying interest here was whether there is a way of doing this that is not O(n) - It sounds like there isn't. Commented Feb 3, 2014 at 15:46
  • JS hardly ever neatly follows those ptime predictions you learned in CS. depending on your needs, Object.create() could be a lot faster. Commented Feb 3, 2014 at 15:47
  • I don't think its even theoretically possible for any operations on each element of an unordered array to be less than O(n). However, isn't O(n) the exact case that most algorithms try to get to? Once you're O(n) you're basically in "not a problem" territory. Commented Feb 3, 2014 at 15:49
  • sure it is, do some repetitive benchmarks in V8 or TraceMonkey and you'll see what i mean. if the routine is compiled and not runtime optimized, the old rules apply. Commented Feb 3, 2014 at 15:50

3 Answers 3

5

Assuming your browser requirements support Array.prototype.reduce

colours.reduce(function(obj, c){ 
  obj[c] = "VAL";
  return obj;
}, {})

or if you're ok with being a jerk and using syntax most js devs aren't even aware exists

colours.reduce(function(obj, c){ return (obj[c] = "VAL", obj) }, {})
Sign up to request clarification or add additional context in comments.

2 Comments

The Syntax is ok and I like this solution, +1!
@Cerbrus some languages call it fold, foldl or aggregate, all the same concept.
4

If you really want to skip loops altogether (Including functions like map), this works:

JSON.parse('{"'+colours.join('":"VAL", "')+'":"VAL"}');

This builds a JSON string, then parses it.

However, I wouldn't use this function. It's ugly, inefficient, hard to maintain, uses loops "under the hood", and it's generally bad form. (I'm not even gonna bother with eval instead of JSON. eval === evil).

Go for something like map instead:

var colours = [ "Red", "Orange", "Yellow", "Green", "Blue", "Indigo", "Violet" ];
var colourMap = {};
colours.forEach(function(c){
    colourMap[c] = "VAL";
});

Yes, it's looping through the colours, but it's more efficient, and easier to understand.

Regarding performance:

map and reduce seem to be similar in execution speed (reduce is slightly faster), in Google Chrome.

3 Comments

Just a small note: Obviously it will not work with all possible VALs
Yea, the JSON option has to result in valid JSON. Some VALs might break it. (And that's one of the reasons it's a bad option)
JSON.parse uses loops internally so still looping. If you really want to avoid loops you can eval but that is getting so over the top pedantic its absurd.
2

You can do it with jQuery:

colourMap = $.map(colours, function(e){
  return { e: "VAL" };
});

or with Underscore:

var colourMap = {};
_.each(some_object_array, function(val) {
  colourMap[val] = "VAL";
});

Or even better (Thanks to George Mauer):

_.object(_.map(colourMap, function(c) { return [c, "VAL"] }))

5 Comments

With underscore: _.object(_.map(colourMap, function(c) { return [c, "VAL"] })) Usually I use this pattern so much that I do _.mixin({ mapObject: _.compose(_.object, _.map) })
Those are still loops, technically.
Uhm I think your code produce an array of objects, one for each of the colors. Each one has only 1 key...
Yes, I'm afraid I don't have access to jQuery. Pragmatically, I suppose even a one liner could be looping under the covers. I'm really looking for the most efficient way of doing this since it's code which will be called quite frequently.
To @AndreaParodi's point, the jquery example above does not produce what you're after, you would have to do colourMap = $.extend.apply($, ...) to get it all into one object

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.