2016-03-11 16 views
10

Làm cách nào để kiểm tra xem hai đối tượng ES2015 Map có cùng một bộ (key, value) cặp không?Làm cách nào để kiểm tra xem hai đối tượng Bản đồ có bằng nhau không?

Chúng ta có thể giả định rằng tất cả các khóa và giá trị đều là kiểu dữ liệu nguyên thủy.

Một cách tiếp cận để giải quyết vấn đề này là lấy map.entries(), tạo mảng từ đó, sau đó sắp xếp mảng theo các khóa. Và làm điều tương tự với bản đồ khác. Và sau đó lặp qua hai mảng đó để so sánh chúng. Tất cả các đường nối này cồng kềnh và cũng rất kém hiệu quả do phân loại (hiệu suất kém hiệu quả) và do làm cho các mảng đó (không hiệu quả bộ nhớ).

Có ai có ý tưởng tốt hơn không?

+1

cung cấp mã không liên kết –

+0

Cung cấp mã cho cái gì? – Luka

+1

Câu hỏi của bạn. bạn phải tự mình tìm một giải pháp trước khi yêu cầu. của nó trong các quy tắc. bạn phải cung cấp mã ví dụ về những gì bạn đã thử cho đến nay –

Trả lời

12

Không có cách "chuẩn" hoặc "tích hợp sẵn" để thực hiện việc này. Về mặt khái niệm, bạn chỉ cần so sánh hai đối tượng Bản đồ có cùng khóa và giá trị cho mỗi khóa và không có khóa bổ sung.

Để được như hiệu quả về sự so sánh càng tốt, bạn có thể làm tối ưu hóa sau đây:

  1. Đầu tiên kiểm tra .size tài sản trên cả bản đồ. Nếu hai bản đồ không có cùng số lượng khóa, thì bạn biết ngay, chúng không thể giống nhau.
  2. Hơn nữa, đảm bảo rằng chúng có cùng số lượng khóa cho phép bạn chỉ cần lặp lại một trong các bản đồ và so sánh các giá trị của nó với nhau.
  3. Sử dụng cú pháp vòng lặp for (var [key, val] of map1) để lặp lại các khóa, do đó bạn không phải tự mình xây dựng hoặc sắp xếp một dãy khóa (nên cả bộ nhớ nhanh hơn và hiệu quả hơn).
  4. Sau đó, cuối cùng, nếu bạn đảm bảo rằng so sánh trả về ngay khi tìm thấy không phù hợp, thì nó sẽ rút ngắn thời gian thực hiện khi chúng không giống nhau.

Sau đó, vì undefined là một giá trị pháp lý trong một bản đồ, nhưng đó cũng là điều .get() lợi nhuận nếu phím không được tìm thấy, chúng ta phải xem ra cho điều đó bằng cách làm thêm một .has() nếu giá trị chúng ta đang so sánh là undefined. Bởi vì cả hai khóa và giá trị với một đối tượng Map có thể là đối tượng, nên điều này sẽ có nhiều tricker nếu bạn muốn so sánh tài sản sâu sắc của các đối tượng để xác định sự bình đẳng thay vì chỉ đơn giản là === mà Javascript sử dụng theo mặc định để kiểm tra cùng một đối tượng. Hoặc, nếu bạn chỉ quan tâm đến các đối tượng có nguyên thủy cho các khóa và giá trị, thì có thể tránh được sự phức tạp này.

Đối với hàm chỉ kiểm tra bình đẳng giá trị nghiêm ngặt (kiểm tra đối tượng để xem chúng có cùng đối tượng vật lý chứ không phải so sánh thuộc tính sâu), bạn có thể thực hiện những gì được hiển thị bên dưới. Điều này sử dụng cú pháp ES6 để lặp lại hiệu quả các đối tượng bản đồ và các nỗ lực để cải thiện hiệu suất khi chúng không khớp với mạch ngắn và trả lại false ngay sau khi tìm thấy sự không phù hợp.

Đoạn mã này yêu cầu Firefox 41 hoặc Chrome 49. Đoạn mã này không hoạt động trong Edge 25 hoặc IE 11 (có thể do người dùng thuộc loại cú pháp ES2 for/of đang sử dụng). Nó có thể được thực hiện để làm việc trong các trình duyệt khác bằng cách sử dụng công nghệ cũ cho vòng lặp for, nhưng vì điều này đã có tính năng ES6 (đối tượng Bản đồ) và chúng tôi đang cố gắng tối ưu hóa việc triển khai, tôi đã chọn sử dụng ES6 mới nhất cú pháp.

"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>


Nếu bạn muốn làm so sánh đối tượng sâu chứ không chỉ so sánh để xem họ có thể chất cùng một đối tượng, nơi các giá trị có thể là đối tượng hoặc mảng, sau đó cuộc sống trở nên một phức tạp hơn nhiều.

Để làm điều đó, bạn cần một đối tượng phương pháp so sánh sâu mà sẽ đưa vào tài khoản tất cả các nội dung sau:

  1. so sánh đệ quy cho các đối tượng lồng nhau
  2. Bảo vệ chống lại tham chiếu vòng tròn (có thể gây ra một vòng lặp vô hạn)
  3. Tìm hiểu cách so sánh một số loại đối tượng dựng sẵn như Date.

Vì rất nhiều đã được viết ở đâu đó về cách so sánh đối tượng sâu (bao gồm một số câu trả lời được bình chọn cao ở đây trên StackOverflow), tôi cho rằng đó không phải là phần chính của câu hỏi của bạn.

+0

Tại sao bạn lặp lại hai lần? Không nên chỉ vòng lặp đầu tiên đủ như bạn đã kiểm tra các kích thước phù hợp? – Luka

+0

@contrabit - Điểm tốt. Ban đầu tôi không có so sánh '.size' trong đó nên tôi cần vòng lặp thứ hai để xử lý các khóa thừa trong' m2', nhưng bây giờ tôi có so sánh '.size', tôi nghĩ bạn nói đúng. Tôi sẽ loại bỏ vòng lặp thứ hai. – jfriend00

+0

Thêm một kiểm tra cho một trường hợp cạnh nếu một giá trị trong một bản đồ là 'undefined' chính nó, nơi phiên bản đầu tiên của mã sẽ phù hợp với một khóa thiếu bởi vì đó là những gì' .get() 'trả về khi khóa bị thiếu. – jfriend00

1

Nếu bạn Mapchỉ phím chuỗi, sau đó bạn có thể sử dụng phương pháp này để so sánh chúng:

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) 

Lưu ý:deepEqual là một phần của nhiều dãy phòng thử nghiệm và nếu không, bạn có thể sử dụng tương đương lodash/underscore. Bất kỳ chức năng nào so sánh sâu sẽ làm.

mapToObj chức năng kê biếu không của http://exploringjs.com/es6/ch_maps-sets.html

Các vấn đề liên quan