比较两个地图对象在Javascript中的平等是什么好的方法? [英] What is a good approach to compare two map objects for equality in Javascript?

查看:108
本文介绍了比较两个地图对象在Javascript中的平等是什么好的方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何查看两个 ES2015 Map 对象具有相同的一组(key,value)对?



我们可以假设所有的键并且值是原始数据类型。



解决这个问题的一种方法是采取 map.entries()从它创建数组,然后按键排序该数组。并与其他地图做同样的事情。然后循环通过这两个数组进行比较。所有这些接缝都是麻烦的,因为排序(性能低效)和因为使这些阵列(内存无效率)而非常低效。



有没有人有更好的想法? >

解决方案

没有标准或内置的方式来做到这一点。在概念上,你只需要比较两个Map对象对于每个键具有相同的键和值,并且没有额外的键。



要比较一下效率可以执行以下优化:


  1. 首先检查 .size 属性在两张地图上。如果两张地图的密钥数量不一样,那么你马上就知道,它们不一样。

  2. 此外,保证它们具有相同数量的键可以让您迭代其中的一个地图,并将其值与另一个进行比较。

  3. 使用迭代键的(var [key,val] of map1)迭代器语法的来迭代键,所以你不必自己构建或排列一个键数组(应该更快,更高的内存效率)。

  4. 然后,最后,如果确保比较在立即发生不匹配时立即返回,那么它会缩短执行时间,因为它们不一样。

然后,因为 undefined 是地图中的合法价值,但是如果没有找到密钥,那么它也是 .get()返回的,我们必须注意如果我们比较的值是未定义

$ b $,请执行额外的 .has() b

由于Map对象的键和值都可以是对象本身,如果要对对象进行深度属性比较来确定相等性而不仅仅是更简单的 === Javascript默认使用以测试同一个对象。或者,如果您只对具有键和值的原语的对象感兴趣,则可以避免这种复杂性。



对于仅测试严格值相等性的函数检查对象以查看它们是否是相同的物理对象,而不是深度属性比较),您可以执行以下所示的操作。这使用ES6语法来有效地迭代地图对象,并尝试通过短路不匹配来提高性能,并在发现不匹配时返回 false 。 p>

此代码段需要Firefox 41或Chrome 49.它在Edge 25或IE 11中不起作用(可能是因为用户的类型为 ES6语法正在使用)。通过使用较旧的技术,可以使用循环中的在其他浏览器中工作,但由于这已经是关于ES6功能(Map对象),我们是尝试优化实现,我选择使用最新的ES6语法。



  use strict; function compareMaps(map1,map2){var testVal; if(map1.size!== map2.size){return false; } for(var [key,val] of map1){testVal = map2.get(key); //在一个未定义的值的情况下,确保键//实际上存在于对象上,因此如果(testVal!== val ||(testVal === undefined&!map2.has( key))){return false; }} //返回true;} //构造两个最初相同的映射v = o{k:2} var m1 = new Map(); m1.set(obj,o); m1.set(str0 ,未定义); m1.set(str1,1); m1.set(str2,2); m1.set(str3,3); var m2 = new Map(); m2.set (str1,1); m2.set(str2,2); m2.set(str3,3); log(compareMaps(m1,m2)); //将一个未定义的键添加到m1和一个相应的其他键到m2 //这将通过.size测试,甚至通过相等测试,但不通过//特殊测试未定义的值m1.set(str-undefined,undefined); m2.set(str4,4); log(compareMaps(m1,m2)); //从m1中删除一个键,所以m2有一个额外的keym1.delete (str-undefined); log(compareMaps(m1,m2)); //将相同的额外键添加到m1,但给它一个不同的值memset1.set(str4,5); log(compareMaps(m1, m2));  

 < script src =http: //files.the-friend-family.com/log.js\"></script>  






如果你想做深层对象的比较,而不是只是比较,看看他们是物理上是相同的对象,值可以要做对象或数组,那么生活会变得更复杂一些。



为了做到这一点,你需要一个深入的对象比较方法来考虑以下所有的内容: p>


  1. 嵌套对象的递归比较

  2. 针对循环引用的保护(可能导致无限循环) li>
  3. 知道如何比较某些类型的内置对象,例如 Date

由于在别的地方写了很多关于如何进行深层对象比较(包括StackOverflow上的一些高度评价的答案),我将假设这不是主要部分你的问题。


How can I check if two ES2015 Map objects have the same set of (key, value) pairs?

We can assume that all the keys and values are primitive datatypes.

One approach to solve this would be to take the map.entries(), create array from it, then sort that array by keys. And do the same thing with the other map. And then loop through those two arrays to compare them. All this seams cumbersome and also very inefficient because of sorting (performance inefficiency) and because of making those arrays (memory inefficiency).

Does anybody have better idea?

解决方案

There is no "standard" or "built-in" way to do this. Conceptually, you just have to compare that the two Map objects have the same keys and values for each key and have no extra keys.

To be as efficient about the comparison as possible, you can do the following optimizations:

  1. First check the .size property on both maps. If the two maps don't have the same number of keys, then you know right away, they can't be identical.
  2. Furthermore, guaranteeing that they have the same number of keys allows you to just iterate one of the maps and compare its values to the other.
  3. Use the for (var [key, val] of map1) iterator syntax for iterating the keys so you don't have to build or sort an array of keys yourself (should be both faster and more memory efficient).
  4. Then, lastly, if you make sure that the comparison returns immediately as soon as a mismatch is found, then it will shorten the execution time when they are not the same.

Then, since undefined is a legal value in a Map, but it's also what .get() returns if the key is not found, we have to watch out for that by doing an extra .has() if the value we're comparing is undefined.

Since both keys and values with a Map object can be objects themselves, this gets much tricker if you want a deep property comparison of objects to determine equality rather than just the more simple === that Javascript uses by default to test for the same object. Or, if you're only interested in objects that have primitives for keys and values, then this complexity can be avoided.

For a function that tests only strict value equality (checks objects to see if they are the same physical object, not a deep property comparison), you can do what is shown below. This uses ES6 syntax for efficient iteration of the map objects and attempts to improve performance when they do not match by short circuiting and returning false as soon as a mismatch is found.

This snippet requires Firefox 41 or Chrome 49. It does not work in Edge 25 or IE 11 (probably because of the user of the type of for/of ES6 syntax it is using). It could be made to work in other browsers by using older tech for the for loop, but since this is already about an ES6 feature (the Map object) anyway and we're trying to optimize the implementation, I chose to use the latest ES6 syntax.

"use strict";

function compareMaps(map1, map2) {
    var testVal;
    if (map1.size !== map2.size) {
        return false;
    }
    for (var [key, val] of map1) {
        testVal = map2.get(key);
        // in cases of an undefined value, make sure the key
        // actually exists on the object so there are no false positives
        if (testVal !== val || (testVal === undefined && !map2.has(key))) {
            return false;
        }
    }
    return true;
}

// construct two maps that are initially identical
var o = {"k" : 2}

var m1 = new Map();
m1.set("obj", o);
m1.set("str0", undefined);
m1.set("str1", 1);
m1.set("str2", 2);
m1.set("str3", 3);

var m2 = new Map();
m2.set("str0", undefined);
m2.set("obj", o);
m2.set("str1", 1);
m2.set("str2", 2);
m2.set("str3", 3);

log(compareMaps(m1, m2));

// add an undefined key to m1 and a corresponding other key to m2
// this will pass the .size test and even pass the equality test, but not pass the
// special test for undefined values
m1.set("str-undefined", undefined);
m2.set("str4", 4);
log(compareMaps(m1, m2));

// remove one key from m1 so m2 has an extra key
m1.delete("str-undefined");
log(compareMaps(m1, m2));

// add that same extra key to m1, but give it a different value
m1.set("str4", 5);
log(compareMaps(m1, m2));

<script src="http://files.the-friend-family.com/log.js"></script>


If you wanted to do deep object comparison rather than just comparing to see if they are physically the same object, where values could be objects or arrays, then life gets a lot more complicated.

To do that, you need a deep object comparison method that takes into account all of the following:

  1. Recursive comparison for nested objects
  2. Protection against circular references (which can cause an infinite loop)
  3. Knowledge of how to compare some types of built-in objects such as a Date.

Since a lot has been written elsewhere about how to do a deep object comparison (including a number of highly voted answers here on StackOverflow), I will assume that is not the main part of your question.

这篇关于比较两个地图对象在Javascript中的平等是什么好的方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆