Sử dụng lodash để so sánh các mảng (các mục tồn tại không theo thứ tự)


124

Tôi biết tôi có thể làm điều đó bằng cách sử dụng các vòng lặp, nhưng tôi đang cố gắng tìm một cách thanh lịch để làm điều này:

Tôi có hai mảng:

var array1 = [['a', 'b'], ['b', 'c']];
var array2 = [['b', 'c'], ['a', 'b']];

Tôi muốn sử dụng lodashđể xác nhận rằng hai mảng trên là giống nhau. Bởi 'giống nhau', ý tôi là không có vật phẩm nào trong array1đó không được chứa trong array2.

Về mặt kiểm tra sự bình đẳng giữa các mục này:

['a', 'b'] == ['b', 'a'] 

hoặc là

['a', 'b'] == ['a', 'b'] 

Cả hai đều hoạt động vì các chữ cái sẽ luôn theo thứ tự.

Câu trả lời:


224

Nếu bạn sắp xếp mảng bên ngoài, bạn có thể sử dụng _.isEqual()vì mảng bên trong đã được sắp xếp.

var array1 = [['a', 'b'], ['b', 'c']];
var array2 = [['b', 'c'], ['a', 'b']];
_.isEqual(array1.sort(), array2.sort()); //true

Lưu ý rằng điều đó .sort()sẽ làm thay đổi các mảng. Nếu đó là vấn đề với bạn, trước tiên hãy tạo một bản sao bằng cách sử dụng (ví dụ) .slice()hoặc toán tử spread ( ...).

Hoặc, làm như Daniel Budick đề xuất trong một bình luận bên dưới:

_.isEqual(_.sortBy(array1), _.sortBy(array2))

Lodash's sortBy()sẽ không làm thay đổi mảng.


6
Lưu ý rằng array.sort () đang thay đổi mảng ban đầu. Có lẽ cái này có thể tốt hơn: var array1 = [['a', 'b'], ['b', 'c']]; var array2 = [['b', 'c'], ['a', 'b']]; _.isEqual ([... array1] .sort (), [... array2] .sort ()); // true
Yaniv Efraim

3
Đã thêm hai câu lưu ý rằng các .sort()biến đổi và đề xuất các tùy chọn sao chép trước nếu đó là vấn đề đối với người dùng.
Trott

6
Nếu bạn đã sử dụng lodash, bạn chỉ có thể làm _.isEqual(_.sortBy(array1), _sortBy(array2))để ngăn chặn đột biến.
Daniel Budick

1
@DanielBudick Cảm ơn! Tôi đã thêm điều đó vào câu trả lời. Gợi ý tuyệt vời.
Trott

31

Bạn có thể sử dụng lodashs xorcho việc này

doArraysContainSameElements = _.xor(arr1, arr2).length === 0

Nếu bạn coi mảng [1, 1] khác với mảng [1] thì bạn có thể cải thiện hiệu suất một chút như vậy:

doArraysContainSameElements = arr1.length === arr2.length === 0 && _.xor(arr1, arr2).length === 0

1
Mảng dù sao cũng cần được sắp xếp.
Sovattha Sok

1
Đây sẽ là cách tốt hơn cho phiên bản mới hơn
Leonardo

@Sovattha Sok Các mảng không cần phải được sắp xếp. Làm _.xor([3,4], [4,3]).length == 0sẽ giúp bạn trở thành sự thật.
Nikolay

1
Một lời cảnh báo: Kỹ thuật này hoạt động tốt đối với các mảng "nhỏ" nhưng nó có thể là một hiệu suất khó khăn và tốn bộ nhớ nếu các mảng của bạn lớn và hầu hết là khác nhau vì _.xor () sẽ tiếp tục đi qua điểm khác biệt đầu tiên. Nói cách khác, nó không trở lại nhanh khi phát hiện sự khác biệt đầu tiên.
XDS

6

Bởi 'giống nhau', ý tôi là không có mục nào trong mảng1 không được chứa trong mảng2.

Bạn có thể sử dụng flatten () và chênh lệch () cho điều này, trong đó hoạt động tốt nếu bạn không quan tâm nếu có các mục trong array2đó không phải là trong array1. Có vẻ như bạn đang hỏi array1 có phải là tập con của array2 không?

var array1 = [['a', 'b'], ['b', 'c']];
var array2 = [['b', 'c'], ['a', 'b']];

function isSubset(source, target) {
    return !_.difference(_.flatten(source), _.flatten(target)).length;
}

isSubset(array1, array2); // → true
array1.push('d');
isSubset(array1, array2); // → false
isSubset(array2, array1); // → true

4

Đã có câu trả lời ở đây, nhưng đây là cách triển khai JS thuần túy của tôi. Tôi không chắc liệu nó có tối ưu không, nhưng nó chắc chắn là minh bạch, dễ đọc và đơn giản.

// Does array a contain elements of array b?
const contains = (a, b) => new Set([...a, ...b]).size === a.length
const isEqualSet = (a, b) => contains(a, b) && contains(b, a)

Cơ sở lý luận contains()là if achứa tất cả các phần tử củab , thì việc đặt chúng vào cùng một tập hợp sẽ không thay đổi kích thước.

Ví dụ, nếu const a = [1,2,3,4]const b = [1,2], sau đó new Set([...a, ...b]) === {1,2,3,4}. Như bạn có thể thấy, tập hợp kết quả có các phần tử giống nhưa .

Từ đó, để ngắn gọn hơn, chúng ta có thể tóm tắt nó lại như sau:

const isEqualSet = (a, b) => {
  const unionSize = new Set([...a, ...b])
  return unionSize === a.length && unionSize === b.length
}

1

PURE JS (cũng hoạt động khi mảng và mảng con có nhiều hơn 2 phần tử với thứ tự tùy ý). Nếu chuỗi chứa ,sử dụng làm join('-')ký tự tham số (có thể là utf) không được sử dụng trong chuỗi

array1.map(x=>x.sort()).sort().join() === array2.map(x=>x.sort()).sort().join()


0

Chúng ta có thể sử dụng _.differencechức năng để xem có sự khác biệt nào hay không.

function isSame(arrayOne, arrayTwo) {
   var a = _.unique(arrayOne),
       b = _.unique(arrayTwo);

   if (a.length <= b.length) {
      a = arrayTwo;
      b = arrayOne;
      return _.isEmpty(_.difference(a.sort(), b.sort()));
   } else {
      return false;
   }

}

// examples
console.log(isSame([1, 2, 3], [1, 2, 3])); // true
console.log(isSame([1, 2, 4], [1, 2, 3])); // false
console.log(isSame([1, 2], [2, 3, 1])); // false
console.log(isSame([2, 3, 1], [1, 2])); // false

// Test cases pointed by Mariano Desanze, Thanks.
console.log(isSame([1, 2, 3], [1, 2, 2])); // false
console.log(isSame([1, 2, 2], [1, 2, 2])); // true
console.log(isSame([1, 2, 2], [1, 2, 3])); // false

Tôi hy vọng điều này sẽ giúp bạn.


5
Sai, chức năng của bạn sẽ nhận được truechoconsole.log(isSame([1,2], [2,3,1]));
David Lin

3
Cảm ơn bạn @DavidLin đã chỉ ra điều đó. Tôi đã thực hiện các thay đổi để xem xét trường hợp đó. Cảm ơn bạn và xin lỗi vì sự bất tiện này.
Amitesh

2
bạn không cần phải đổi chỗ cho a & b nếu độ dài không giống nhau. Nếu độ dài khác nhau thì chúng không thể giống nhau được, vì vậy if (arrayOne.lenght! == arrayTwo.lenght) return false;
Alex

1
-1 Không có nghĩa là có những abcác biến. Bạn chỉ sử dụng các biến bên trong if-thenmột phần, và điều đầu tiên bạn làm ở đó được loại bỏ những giá trị nạp tại dòng 2. Tôi nghĩ rằng dòng sau đây sẽ làm việc giống hệt nhau: return arrayOne.length <= arrayTwo.length && _.isEmpty(_.difference(arrayTwo.sort(), arrayTwo.sort());. Và <=cũng có thể được cải thiện thành ===.
Mariano Desanze

1
_.differencesẽ trả về các mục bị thiếu của đối số thứ nhất, nhưng không bị thiếu các mục trong đối số thứ hai. Vì vậy, đây không đúng cách sẽ trở lại truekhi bạn lặp lại các mục trên 1 trong 2: isSame([1, 2, 3], [1, 2, 2]).
Mariano Desanze

0

Chỉnh sửa: Tôi đã bỏ lỡ khía cạnh đa chiều của câu hỏi này, vì vậy tôi để điều này ở đây trong trường hợp nó giúp mọi người so sánh các mảng một chiều

Đó là một câu hỏi cũ, nhưng tôi đã gặp vấn đề với tốc độ sử dụng .sort()hoặc sortBy(), vì vậy tôi đã sử dụng câu hỏi này để thay thế:

function arraysContainSameStrings(array1: string[], array2: string[]): boolean {
  return (
    array1.length === array2.length &&
    array1.every((str) => array2.includes(str)) &&
    array2.every((str) => array1.includes(str))
  )
}

Nó dự định sẽ hỏng nhanh, và đối với mục đích của tôi, hoạt động tốt.


Lần kiểm tra cuối cùng có thực sự cần thiết? array1.every((str) => array2.includes(str))nên là đủ. Ngoài ra OP muốn sử dụng lodash, ít nhất bạn nên nói lý do tại sao bạn đề xuất giải pháp vaniJS (... bây giờ chúng tôi có mọi và bao gồm ...). Vui lòng cung cấp một ví dụ về cách áp dụng hàm của bạn cho vấn đề được cung cấp (mảng 2 chiều).
line-o

Đó là một điểm tốt - tôi đã không đề cập đến khía cạnh đa chiều của nó, không phải là yêu cầu về lodash. Tôi nghĩ rằng sẽ hữu ích nếu bất kỳ ai đang tìm kiếm (như tôi đã làm) lodash methods to compare arrays without considering orderđể xem một giải pháp thay thế trong Javascript hiện đại. Việc kiểm tra thứ hai là cần thiết vì arraysContainSameStrings(['1', '2', '2'], ['1', '2', '3'])nếu không sẽ trả về true. Tôi sẽ để nó ở đây, vì nó có thể hữu ích, nhưng tôi đánh giá cao tôi chưa trả lời câu hỏi
charliematters
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.