I'm trying to use the new (ES6) Map
objects in order to represent a map between properties and a value.
I have objects in a form similar to:
{key1:value1_1,key2:value2_1},..... {key1:value1_N,key2:value2_N}
I want to group them based on both their key1 and key2 value.
For example, I want to be able to group the following by x
and y
:
[{x:3,y:5,z:3},{x:3,y:4,z:4},{x:3,y:4,z:7},{x:3,y:1,z:1},{x:3,y:5,z:4}]
And obtain a Map containing:
{x:3,y:5} ==> {x:3,y:5,z:3},{x:3,y:5,z:4} {x:3,y:4} ==> {x:3,y:4,z:4},{x:3,y:4,z:7} {x:3,y:1} ==> {x:3,y:1,z:1}
In Python, I'd use tuples as dictionary keys. ES6 map allow arbitrary objects as keys but use the standard equality algorithm (===
) so objects are only equal by reference from what I can tell.
How can I accomplish this sort of grouping using ES6 maps? Alternatively, a solution using normal JS objects if there is an elegant way I overlooked.
I'd rather not use an external collections library - but if there is a better solution using one I'm interested in learning about it too.
a pair is a tuple that only holds two values. a map is a structure that (conceptually) holds multiple pairs and allows efficient lookups by the first element in the pair (the key). They also do not allow the first elements of any pairs to be the same.
Map can also use objects as keys. The same does not count for Object . String as a key in Object is fine, but we can't use another Object as a key in Object .
get(): It is used to access the tuple values and modify them, it accepts the index and tuple name as arguments to access a particular tuple element. What is map? Maps in C++ are associative containers that can store elements in a mapped fashion. Each element of a map has a key and the corresponding mapped value.
An object behaves like a dictionary because JavaScript is dynamically typed, allowing you to add or remove properties at any time. But Map() is much better because it: Provides get , set , has , and delete methods. Accepts any type for the keys instead of just strings.
It doesn’t seem conveniently possible. What can you do? Something horrible, as always.
let tuple = (function() { let map = new Map(); function tuple() { let current = map; let args = Object.freeze(Array.prototype.slice.call(arguments)); for (let item of args) { if (current.has(item)) { current = current.get(item); } else { let next = new Map(); current.set(item, next); current = next; } } if (!current.final) { current.final = args; } return current.final; } return tuple; })();
And voilà.
let m = new Map(); m.set(tuple(3, 5), [tuple(3, 5, 3), tuple(3, 5, 4)]); m.get(tuple(3, 5)); // [[3, 5, 3], [3, 5, 4]]
Ok, I've raised the issue on esdiscuss now and I got an answer from Mozilla's Jason Orendorff:
.equals
and .hashCode
but it was rejected in favor of value objects. (for good reasons in my opinion).A basic such collection (concept, don't use in production code) was offered by Bradley on the ESDiscuss thread and might look something like this:
function HashMap(hash) { var map = new Map; var _set = map.set; var _get = map.get; var _has = map.has; var _delete = map.delete; map.set = function (k,v) { return _set.call(map, hash(k), v); } map.get = function (k) { return _get.call(map, hash(k)); } map.has = function (k) { return _has.call(map, hash(k)); } map.delete = function (k) { return _delete.call(map, hash(k)); } return map; } function TupleMap() { return new HashMap(function (tuple) { var keys = Object.keys(tuple).sort(); return keys.map(function (tupleKey) { // hash based on JSON stringification return JSON.stringify(tupleKey) + JSON.stringify(tuple[tupleKey]); }).join('\n'); return hashed; }); }
A better solution is to use something like MontageJS/Collections which allows for specification of hash/equals functions.
You can see the API docs here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With