如何检查两个Map对象是否相等?

时间:2016-03-11 19:26:06

标签: javascript dictionary

如何检查两个ES2015 Map对象是否具有相同的(key, value)对?

我们可以假设所有键和值都是原始数据类型。

解决此问题的一种方法是从中map.entries()创建数组,然后按键对该数组进行排序。并与其他地图做同样的事情。然后遍历这两个数组来比较它们。由于排序(性能低效)以及制作这些阵列(内存效率低下),所有这些接缝都很麻烦且效率也很低。

有没有人有更好的想法?

4 个答案:

答案 0 :(得分:21)

没有“标准”或“内置”方式来执行此操作。从概念上讲,您只需比较两个Map对象对每个键具有相同的键和值,并且没有额外的键。

为了尽可能提高比较效率,您可以进行以下优化:

  1. 首先检查两张地图上的Option Explicit 'Use every time will keep you from making simple mistakes... Sub test() Dim wb As Workbook Dim ws As Worksheet Dim wbSource As Workbook Dim i As Integer On Error GoTo ErrCatch 'add to catch errors Set wb = Application.ThisWorkbook Set ws = wb.Worksheets("Sheet1") For i = 1 To 5 '## Open workbooks: Set wbSource = Workbooks.Open("C:\Folder\" & ws.Cells(i, 2).Value & ".xlsx") 'Cells(Row,Column) 2 = "B" 'Copy from wbSource and paste in worksheet wbSource.Sheets("Summary").Range("D13:F13").Copy Destination:=ws.Cells(i, 3) 'This syntax keeps you from having to do "Application.CutCopyMode = False" to remove the marching ants. 'Close source: wbSource.Close False Next i ErrCatch: If Err.Number > 1 Then 'test if an error was thrown MsgBox "Error Number: " & Err.Number & vbCrLf & _ "Error Description: " & Err.Description, vbCritical End If End Sub 属性。如果两张地图的密钥数量不同,那么您就知道它们不能完全相同。
  2. 此外,保证它们具有相同数量的键允许您只迭代其中一个映射并将其值与另一个映射进行比较。
  3. 使用.size迭代器语法来迭代密钥,这样您就不必自己构建或排序密钥数组(应该更快,更节省内存)。
  4. 然后,最后,如果确定一旦发现不匹配就立即返回比较,那么当它们不相同时,它将缩短执行时间。
  5. 然后,由于for (var [key, val] of map1)是Map中的合法值,但如果找不到密钥,它也是undefined返回的值,我们必须通过额外{{1}来注意如果我们比较的值是.get()

    由于具有Map对象的键和值都可以是对象本身,如果您希望对象的深度属性比较来确定相等性而不仅仅是Javascript默认使用的更简单.has(),那么这会变得非常棘手。测试同一个对象。或者,如果您只对具有键和值基元的对象感兴趣,则可以避免这种复杂性。

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

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

    for/of

    如果你想进行深度对象比较,而不是仅仅比较它们是否在物理上是同一个对象,其中值可以是对象或数组,那么生活会变得更加复杂。

    要做到这一点,您需要一个深度对象比较方法,该方法考虑以下所有因素:

    1. 嵌套对象的递归比较
    2. 防止循环引用(可能导致无限循环)
    3. 了解如何比较某些类型的内置对象,例如for
    4. 由于其他地方已经写了很多关于如何进行深度对象比较的内容(包括StackOverflow上的一些高度评价的答案),我认为这不是你问题的主要部分。

答案 1 :(得分:2)

如果您的Map只有 字符串键,那么您可以使用此方法进行比较:

const mapToObj = (map) => {
  let obj = Object.create(null)
  for (let [k,v] of map) {
    // We don’t escape the key '__proto__'
    // which can cause problems on older engines
    obj[k] = v
  }
  return obj
}

assert.deepEqual(mapToObj(myMap), myExpectedObj)

注意: deepEqual是许多测试套件的一部分,如果没有,您可以使用lodash / underscore等效项。任何进行深度比较的函数都可以。

mapToObj功能由http://exploringjs.com/es6/ch_maps-sets.html

提供

答案 2 :(得分:0)

以上内容不适用于Map<string, object>,因为以下行将无法正确评估两个对象:

if (testVal !== val || (testVal === undefined && !map2.has(key))) {

以下版本通过使用JSON.stringify()进行比较,扩展了Map<string, object>的功能

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 (JSON.stringify(testVal) !== JSON.stringify(val) || (testVal === undefined && !map2.has(key))) {
            return false;
        }
    }
    return true;
}

答案 3 :(得分:-2)

请注意@ jfriend00提出的解决方案在打字稿ES2016中不起作用。请参阅以获得正确答案:iteration over a typescript map failing