Javascript 使用元组或对象进行映射
我试图使用新的(ES6)对象来表示属性和值之间的映射 我的对象的形式类似于:Javascript 使用元组或对象进行映射,javascript,map,equality,ecmascript-harmony,Javascript,Map,Equality,Ecmascript Harmony,我试图使用新的(ES6)对象来表示属性和值之间的映射 我的对象的形式类似于: {key1:value1_1,key2:value2_1},..... {key1:value1_N,key2:value2_N} 我想根据它们的key1和key2值对它们进行分组 例如,我希望能够通过x和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}] 并获取包含以下内容的地图: {x:3,y:
{key1:value1_1,key2:value2_1},..... {key1:value1_N,key2:value2_N}
我想根据它们的key1和key2值对它们进行分组
例如,我希望能够通过x
和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}]
并获取包含以下内容的地图:
{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}
在Python中,我使用元组作为字典键。ES6 map允许任意对象作为键,但使用标准的相等算法(===
),因此根据我的判断,对象仅通过引用相等
如何使用ES6映射完成这种分组?或者,如果我忽略了一种优雅的方式,那么可以使用普通JS对象的解决方案
我不想使用外部收藏库,但如果有更好的解决方案,我也有兴趣了解它。这似乎不太可能。你能做什么?像往常一样,有些可怕的事情
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;
})();
瞧
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]]
好的,我现在已经提出了这个问题,我从Mozilla得到了一个答案:
.equals
和.hashCode
,但后来被拒绝,取而代之的是值对象。(我认为有充分的理由)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;
});
}
一个更好的解决方案是使用类似的东西,它允许指定hash/equals函数
您可以看到API文档。Benjamin的答案并不适用于所有对象,因为它依赖于JSON.stringify,它不能处理循环对象,并且可以将不同的对象映射到同一个字符串。Minitech的答案可以创建巨大的嵌套映射树,我怀疑这会导致内存和CPU效率低下,特别是对于长元组,因为它必须为元组中的每个元素创建映射 如果您知道元组只包含数字,那么最好的解决方案是使用
[x,y].join(',')
作为键。如果要使用包含任意对象的元组作为键,仍然可以使用此方法,但必须首先将对象映射到唯一标识符。在下面的代码中,我使用get\u object\u id
惰性地生成这些标识符,它将生成的id存储在内部映射中。然后,我可以通过连接这些ID为元组生成键。(请参阅此答案底部的代码。)
然后可以使用tuple
方法将对象的元组散列为字符串,该字符串可以用作映射中的键。这使用了对象等价性:
x={}; y={};
tuple(x,y) == tuple(x,y) // yields true
tuple(x,x) == tuple(y,y) // yields false
tuple(x,y) == tuple(y,x) // yields false
如果确定元组只包含对象(即不为null、数字或字符串),则可以在get\u object\u id
中使用WeakMap,这样get\u object\u id
和tuple
就不会泄漏作为参数传递给它们的对象
var get\u object\u id=(函数(){
生成的var_id=1;
var map=newmap();
返回get\u object\u id;
函数获取对象id(obj){
如果(映射has(obj)){
返回map.get(obj);
}否则{
var r=生成的_id++;
地图集(obj,r);
返回r;
}
}
})();
函数元组(){
返回Array.prototype.map.call(参数,get_object_id).join(',');
}
//试验
var data=[{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}];
var map=newmap();
对于(var i=0;i虽然这个问题已经很老了,但值对象在JavaScript中仍然不是一个存在的东西(因此人们可能仍然感兴趣),所以我决定编写一个简单的库来实现数组作为映射中键的类似行为(repo here:)。库的设计基本上与map相同,只是数组按元素而不是按标识进行比较
用法:
var map = new ArrayMap();
map.set([{x: 3, y: 5}], {x:3, y:5, z:10});
map.get([{x: 3, y: 5}]); // undefined as objects within the list are
// treated by identity
警告:但是,库按标识处理关键元素,因此以下操作无效:
var serialize = function(point) {
return [point.x, point.y];
};
var map = new ArrayMap(null, serialize);
map.set({x: 10, y: 20}, {x: 10, y: 20, z: 30});
map.get({x: 10, y: 20}); // {x: 10, y: 20, z: 30}
但是,只要可以将数据序列化为基本体数组,就可以按如下方式使用ArrayMap:
多年过去了,这仍然是JavaScript的一个问题。我改进了Jamesernator的方法并创建了该包。现在您可以得到您想要的:
从“集合深度相等”导入{MapDeepEqual,SetDeepEqual};
const object={name:“Leandro”,年龄:29};
const deepEqualObject={name:“Leandro”,年龄:29};
const mapDeepEqual=新的mapDeepEqual();
mapDeepEqual.set(对象,“值”);
断言(mapdepequal.get(object)=“value”);
断言(mapDeepEqual.get(deepEqualObject)=“值”);
const setDeepEqual=新setDeepEqual();
setDeepEqual.add(对象);
断言(setDeepEqual.has(object));
断言(setDeepEqual.has(deepEqualObject));
我不确定是否有可能滥用WeakMap
来提高内存效率。可能没有。你刚才是不是在这里实现了一个元组flyweight:O.+1来提高创造力,但我真的认为这应该在语言层面上解决。请解释为什么你认为我关于WeakMap的句子是错误的。另外,如果你的answer可以不使用JSON.stringify,请更新您的答案以解释如何使用。使用WeakMap可确保元组中使用的对象仍有资格进行垃圾收集。即,如果WeakMap是唯一引用对象的对象,垃圾收集器可以销毁该对象(并将其从WeakMap中删除)。因此,它避免了内存泄漏。对象在WeakMap中用作键,因此如果它们符合垃圾收集的条件,则没有问题。映射用于使用唯一标识符扩展对象,而不实际更改对象。--要用另一个哈希函数替换答案中的JSON.stringify,还需要创建其他此类哈希函数函数,这很难。我的tuple()
就是这样一个散列函数,
var serialize = function(point) {
return [point.x, point.y];
};
var map = new ArrayMap(null, serialize);
map.set({x: 10, y: 20}, {x: 10, y: 20, z: 30});
map.get({x: 10, y: 20}); // {x: 10, y: 20, z: 30}