Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
127 views
in Technique[技术] by (71.8m points)

javascript - Map using tuples or objects

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Ok, I've raised the issue on esdiscuss now and I got an answer from Mozilla's Jason Orendorff:

  1. This is a problem with ES6 maps.
  2. The solution will come in the form of ES7 value objects for keys instead of objects.
  3. It was considered before to let people specify .equals and .hashCode but it was rejected in favor of value objects. (for good reasons in my opinion).
  4. The only solution as of now is to roll your own collection.

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('
');
    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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...