Mã đơn giản nhất, không có thư viện để thực hiện các giao điểm mảng trong javascript là gì? tôi muốn viết
intersection([1,2,3], [2,3,4,5])
và lấy
[2, 3]
break
để Simple js loops
tăng ops / giây lên ~ 10M
Mã đơn giản nhất, không có thư viện để thực hiện các giao điểm mảng trong javascript là gì? tôi muốn viết
intersection([1,2,3], [2,3,4,5])
và lấy
[2, 3]
break
để Simple js loops
tăng ops / giây lên ~ 10M
Câu trả lời:
Sử dụng kết hợp Array.prototype.filter
và Array.prototype.indexOf
:
array1.filter(value => -1 !== array2.indexOf(value))
Hoặc như vrugtehagel đã đề xuất trong các nhận xét, bạn có thể sử dụng mã gần đây hơn Array.prototype.includes
cho mã đơn giản hơn:
array1.filter(value => array2.includes(value))
Đối với các trình duyệt cũ hơn:
array1.filter(function(n) {
return array2.indexOf(n) !== -1;
});
intersection([1,2,1,1,3], [1])
trả lại [1, 1, 1]
. Nó không nên trở lại chỉ [1]
?
array2.indexOf(n) != -1
người ta cũng có thể viết array2.includes(n)
cho mã thậm chí đơn giản hơn.
Phá hủy có vẻ đơn giản nhất, đặc biệt nếu chúng ta có thể giả sử đầu vào được sắp xếp:
/* destructively finds the intersection of
* two arrays in a simple fashion.
*
* PARAMS
* a - first array, must already be sorted
* b - second array, must already be sorted
*
* NOTES
* State of input arrays is undefined when
* the function returns. They should be
* (prolly) be dumped.
*
* Should have O(n) operations, where n is
* n = MIN(a.length, b.length)
*/
function intersection_destructive(a, b)
{
var result = [];
while( a.length > 0 && b.length > 0 )
{
if (a[0] < b[0] ){ a.shift(); }
else if (a[0] > b[0] ){ b.shift(); }
else /* they're equal */
{
result.push(a.shift());
b.shift();
}
}
return result;
}
Không phá hủy phải phức tạp hơn, vì chúng tôi phải theo dõi các chỉ số:
/* finds the intersection of
* two arrays in a simple fashion.
*
* PARAMS
* a - first array, must already be sorted
* b - second array, must already be sorted
*
* NOTES
*
* Should have O(n) operations, where n is
* n = MIN(a.length(), b.length())
*/
function intersect_safe(a, b)
{
var ai=0, bi=0;
var result = [];
while( ai < a.length && bi < b.length )
{
if (a[ai] < b[bi] ){ ai++; }
else if (a[ai] > b[bi] ){ bi++; }
else /* they're equal */
{
result.push(a[ai]);
ai++;
bi++;
}
}
return result;
}
intersect_safe
: length
là một thuộc tính trong Mảng, không phải là một phương thức. Có một biến không mong muốn i
trong result.push(a[i]);
. Cuối cùng, điều này chỉ đơn giản là không hoạt động trong trường hợp chung: hai đối tượng không lớn hơn đối tượng khác theo >
toán tử không nhất thiết phải bằng nhau. intersect_safe( [ {} ], [ {} ] )
, ví dụ, sẽ đưa ra (một khi các lỗi đã đề cập trước đó được sửa) một mảng có một phần tử, điều này rõ ràng là sai.
.slice(0)
để tạo một bản sao của mảng intersect_safe
, thay vì theo dõi các chỉ mục.
Nếu môi trường của bạn hỗ trợ ECMAScript 6 Set , một cách đơn giản và được cho là hiệu quả (xem liên kết đặc tả):
function intersect(a, b) {
var setA = new Set(a);
var setB = new Set(b);
var intersection = new Set([...setA].filter(x => setB.has(x)));
return Array.from(intersection);
}
Ngắn hơn, nhưng ít đọc hơn (cũng không tạo giao lộ bổ sung Set
):
function intersect(a, b) {
return [...new Set(a)].filter(x => new Set(b).has(x));
}
Tránh một cái mới Set
từ b
mọi lúc:
function intersect(a, b) {
var setB = new Set(b);
return [...new Set(a)].filter(x => setB.has(x));
}
Lưu ý rằng khi sử dụng các bộ bạn sẽ chỉ nhận được các giá trị riêng biệt, do đó sẽ new Set[1,2,3,3].size
ước tính 3
.
[...setA]
cú pháp này là gì? Một số loại hoạt động javascript đặc biệt?
x => new Set(b).has(x)
chức năng mũi tên đó biến b
thành một tập hợp mỗi khi nó được thực thi sao? Bạn có thể nên lưu tập hợp đó trong một biến.
Sử dụng Underscore.js hoặc lodash.js
_.intersection( [0,345,324] , [1,0,324] ) // gives [0,324]
Đóng góp của tôi trong các điều khoản ES6. Nói chung, nó tìm thấy giao điểm của một mảng với số lượng mảng không xác định được cung cấp làm đối số.
Array.prototype.intersect = function(...a) {
return [this,...a].reduce((p,c) => p.filter(e => c.includes(e)));
}
var arrs = [[0,2,4,6,8],[4,5,6,7],[4,6]],
arr = [0,1,2,3,4,5,6,7,8,9];
document.write("<pre>" + JSON.stringify(arr.intersect(...arrs)) + "</pre>");
[[0,1,2,3,4,5,6,7,8,9],[0,2,4,6,8],[4,5,6,7],[4,6]]
và sau đó áp dụng .reduce()
. [0,1,2,3,4,5,6,7,8,9].filter( e => [0,2,4,6,8].includes(e)
Hoạt động đầu tiên được thực hiện và kết quả trở thành mới p
và c
trở thành [4,5,6,7]
trong lượt tiếp theo và tiếp tục như vậy cho đến khi không còn nữa c
.
prototype
không cần thiết.
// Return elements of array a that are also in b in linear time:
function intersect(a, b) {
return a.filter(Set.prototype.has, new Set(b));
}
// Example:
console.log(intersect([1,2,3], [2,3,4,5]));
Tôi đề xuất giải pháp ngắn gọn ở trên, vượt trội so với các triển khai khác trên các đầu vào lớn. Nếu hiệu suất trên các đầu vào nhỏ có vấn đề, hãy kiểm tra các lựa chọn thay thế bên dưới.
Các lựa chọn thay thế và so sánh hiệu suất:
Xem đoạn mã sau để biết cách triển khai thay thế và kiểm tra https://jsperf.com/array-intersection-comparison để so sánh hiệu suất.
Kết quả trong Firefox 53:
Ops / giây trên mảng lớn (10.000 phần tử):
filter + has (this) 523 (this answer)
for + has 482
for-loop + in 279
filter + in 242
for-loops 24
filter + includes 14
filter + indexOf 10
Ops / giây trên các mảng nhỏ (100 phần tử):
for-loop + in 384,426
filter + in 192,066
for-loops 159,137
filter + includes 104,068
filter + indexOf 71,598
filter + has (this) 43,531 (this answer)
filter + has (arrow function) 35,588
intersect([1,2,2,3], [2,3,4,5])
trả lại [2, 2, 3]
.
a.filter(b.includes)
. Nó sẽ chạy nhanh hơn đáng kể (giống như nâng cấp chức năng của bạn).
Làm thế nào về việc chỉ sử dụng mảng kết hợp?
function intersect(a, b) {
var d1 = {};
var d2 = {};
var results = [];
for (var i = 0; i < a.length; i++) {
d1[a[i]] = true;
}
for (var j = 0; j < b.length; j++) {
d2[b[j]] = true;
}
for (var k in d1) {
if (d2[k])
results.push(k);
}
return results;
}
biên tập:
// new version
function intersect(a, b) {
var d = {};
var results = [];
for (var i = 0; i < b.length; i++) {
d[b[i]] = true;
}
for (var j = 0; j < a.length; j++) {
if (d[a[j]])
results.push(a[j]);
}
return results;
}
Object.prototype
.
d[b[i]] = true;
thay vì d[b[j]] = true;
( i
không j
). Nhưng chỉnh sửa đòi hỏi 6 ký tự.
Một cái gì đó như thế này, Không được thử nghiệm mặc dù.
function intersection(x,y){
x.sort();y.sort();
var i=j=0;ret=[];
while(i<x.length && j<y.length){
if(x[i]<y[j])i++;
else if(y[j]<x[i])j++;
else {
ret.push(x[i]);
i++,j++;
}
}
return ret;
}
alert(intersection([1,2,3], [2,3,4,5]));
PS: Thuật toán chỉ dành cho Số và Chuỗi bình thường, giao điểm của mảng đối tượng tùy ý có thể không hoạt động.
Hiệu suất triển khai của @ atk cho các mảng nguyên thủy được sắp xếp có thể được cải thiện bằng cách sử dụng .pop thay vì .shift.
function intersect(array1, array2) {
var result = [];
// Don't destroy the original arrays
var a = array1.slice(0);
var b = array2.slice(0);
var aLast = a.length - 1;
var bLast = b.length - 1;
while (aLast >= 0 && bLast >= 0) {
if (a[aLast] > b[bLast] ) {
a.pop();
aLast--;
} else if (a[aLast] < b[bLast] ){
b.pop();
bLast--;
} else /* they're equal */ {
result.push(a.pop());
b.pop();
aLast--;
bLast--;
}
}
return result;
}
Tôi đã tạo một điểm chuẩn bằng jsPerf: http://bit.ly/P9FrZK . Nó nhanh hơn khoảng ba lần để sử dụng .pop.
a[aLast] > b[bLast]
bằng a[aLast].localeCompare(b[bLast]) > 0
(và tương tự với else if
bên dưới) thì điều này sẽ hoạt động trên chuỗi.
.pop
là O (1) và .shift()
là O (n)
Sử dụng jQuery :
var a = [1,2,3];
var b = [2,3,4,5];
var c = $(b).not($(b).not(a));
alert(c);
c = $(b).filter(a);
, nhưng tôi không khuyên bạn nên dựa vào jQuery cho loại thao tác mảng này vì tài liệu chỉ đề cập rằng nó hoạt động cho các phần tử.
Đối với các mảng chỉ chứa các chuỗi hoặc số, bạn có thể thực hiện một số thứ với cách sắp xếp, theo một số câu trả lời khác. Đối với trường hợp chung của các mảng của các đối tượng tùy ý, tôi không nghĩ bạn có thể tránh làm điều đó một cách lâu dài. Sau đây sẽ cung cấp cho bạn giao điểm của bất kỳ số lượng mảng nào được cung cấp làm tham số cho arrayIntersection
:
var arrayContains = Array.prototype.indexOf ?
function(arr, val) {
return arr.indexOf(val) > -1;
} :
function(arr, val) {
var i = arr.length;
while (i--) {
if (arr[i] === val) {
return true;
}
}
return false;
};
function arrayIntersection() {
var val, arrayCount, firstArray, i, j, intersection = [], missing;
var arrays = Array.prototype.slice.call(arguments); // Convert arguments into a real array
// Search for common values
firstArray = arrays.pop();
if (firstArray) {
j = firstArray.length;
arrayCount = arrays.length;
while (j--) {
val = firstArray[j];
missing = false;
// Check val is present in each remaining array
i = arrayCount;
while (!missing && i--) {
if ( !arrayContains(arrays[i], val) ) {
missing = true;
}
}
if (!missing) {
intersection.push(val);
}
}
}
return intersection;
}
arrayIntersection( [1, 2, 3, "a"], [1, "a", 2], ["a", 1] ); // Gives [1, "a"];
firstArr
hay firstArray
không và không cập nhật tất cả các tham chiếu. Đã sửa.
Nó khá ngắn khi sử dụng ES2015 và Bộ. Chấp nhận các giá trị giống như mảng như Chuỗi và loại bỏ trùng lặp.
let intersection = function(a, b) {
a = new Set(a), b = new Set(b);
return [...a].filter(v => b.has(v));
};
console.log(intersection([1,2,1,2,3], [2,3,5,4,5,3]));
console.log(intersection('ccaabbab', 'addb').join(''));
Bạn có thể sử dụng một Set
như thisArg
của Array#filter
và mất Set#has
như gọi lại.
function intersection(a, b) {
return a.filter(Set.prototype.has, new Set(b));
}
console.log(intersection([1, 2, 3], [2, 3, 4, 5]));
Một điều chỉnh nhỏ đến mức nhỏ nhất ở đây ( giải pháp bộ lọc / indexOf ), cụ thể là tạo một chỉ mục của các giá trị trong một trong các mảng bằng cách sử dụng một đối tượng JavaScript, sẽ giảm thời gian tuyến tính từ O (N * M) xuống "có thể". nguồn1 nguồn2
function intersect(a, b) {
var aa = {};
a.forEach(function(v) { aa[v]=1; });
return b.filter(function(v) { return v in aa; });
}
Đây không phải là giải pháp đơn giản nhất (mã nhiều hơn bộ lọc + indexOf ), cũng không phải là giải pháp nhanh nhất (có thể chậm hơn bởi một yếu tố không đổi so với giao lộ_safe () ), nhưng có vẻ như là một sự cân bằng khá tốt. Đó là về mặt rất đơn giản, trong khi cung cấp hiệu suất tốt, và nó không yêu cầu đầu vào được sắp xếp trước.
Một cách tiếp cận được lập chỉ mục khác có thể xử lý bất kỳ số lượng mảng nào cùng một lúc:
// Calculate intersection of multiple array or object values.
function intersect (arrList) {
var arrLength = Object.keys(arrList).length;
// (Also accepts regular objects as input)
var index = {};
for (var i in arrList) {
for (var j in arrList[i]) {
var v = arrList[i][j];
if (index[v] === undefined) index[v] = 0;
index[v]++;
};
};
var retv = [];
for (var i in index) {
if (index[i] == arrLength) retv.push(i);
};
return retv;
};
Nó chỉ hoạt động cho các giá trị có thể được đánh giá dưới dạng chuỗi và bạn nên chuyển chúng dưới dạng một mảng như:
intersect ([arr1, arr2, arr3...]);
... nhưng nó chấp nhận một cách trong suốt các đối tượng như là tham số hoặc là bất kỳ phần tử nào được giao nhau (luôn trả về mảng các giá trị chung). Ví dụ:
intersect ({foo: [1, 2, 3, 4], bar: {a: 2, j:4}}); // [2, 4]
intersect ([{x: "hello", y: "world"}, ["hello", "user"]]); // ["hello"]
EDIT: Tôi chỉ nhận thấy rằng, theo một cách nào đó, hơi lỗi.
Đó là: Tôi đã mã hóa nó nghĩ rằng các mảng đầu vào không thể chứa các lần lặp lại (như ví dụ được cung cấp không).
Nhưng nếu mảng đầu vào xảy ra có chứa sự lặp lại, điều đó sẽ tạo ra kết quả sai. Ví dụ (sử dụng thực hiện bên dưới):
intersect ([[1, 3, 4, 6, 3], [1, 8, 99]]);
// Expected: [ '1' ]
// Actual: [ '1', '3' ]
May mắn là điều này rất dễ khắc phục bằng cách thêm chỉ mục cấp hai. Đó là:
Thay đổi:
if (index[v] === undefined) index[v] = 0;
index[v]++;
bởi:
if (index[v] === undefined) index[v] = {};
index[v][i] = true; // Mark as present in i input.
... và:
if (index[i] == arrLength) retv.push(i);
bởi:
if (Object.keys(index[i]).length == arrLength) retv.push(i);
Ví dụ hoàn chỉnh:
// Calculate intersection of multiple array or object values.
function intersect (arrList) {
var arrLength = Object.keys(arrList).length;
// (Also accepts regular objects as input)
var index = {};
for (var i in arrList) {
for (var j in arrList[i]) {
var v = arrList[i][j];
if (index[v] === undefined) index[v] = {};
index[v][i] = true; // Mark as present in i input.
};
};
var retv = [];
for (var i in index) {
if (Object.keys(index[i]).length == arrLength) retv.push(i);
};
return retv;
};
intersect ([[1, 3, 4, 6, 3], [1, 8, 99]]); // [ '1' ]
var v =
thêm dòng if (typeof v == 'function') continue;
và nó sẽ bỏ qua việc thêm chức năng vào kết quả. Cảm ơn!
if (typeof v == 'function')
, thì chúng ta có thể sử dụng chuỗi của nó ( v.toString()
) làm khóa cho chỉ mục. Nhưng, chúng ta cần phải làm gì đó để giữ nguyên. Cách dễ nhất để làm như vậy chỉ đơn giản là gán hàm gốc là giá trị thay vì giá trị boolean đơn giản. Nhưng, trong trường hợp đó, deindexaton mới nhất cũng nên được thay đổi để phát hiện điều kiện này và khôi phục đúng giá trị (hàm).
Bạn có thể sử dụng (cho tất cả các trình duyệt trừ IE):
const intersection = array1.filter(element => array2.includes(element));
hoặc cho IE:
const intersection = array1.filter(element => array2.indexOf(element) !== -1);
Với một số hạn chế về dữ liệu của bạn, bạn có thể làm điều đó trong thời gian tuyến tính !
Đối với các số nguyên dương : sử dụng một mảng ánh xạ các giá trị thành một boolean "nhìn thấy / không nhìn thấy".
function intersectIntegers(array1,array2) {
var seen=[],
result=[];
for (var i = 0; i < array1.length; i++) {
seen[array1[i]] = true;
}
for (var i = 0; i < array2.length; i++) {
if ( seen[array2[i]])
result.push(array2[i]);
}
return result;
}
Có một kỹ thuật tương tự cho các đối tượng : lấy một khóa giả, đặt nó thành "true" cho từng phần tử trong mảng1, sau đó tìm khóa này trong các phần tử của mảng2. Dọn dẹp khi bạn hoàn thành.
function intersectObjects(array1,array2) {
var result=[];
var key="tmpKey_intersect"
for (var i = 0; i < array1.length; i++) {
array1[i][key] = true;
}
for (var i = 0; i < array2.length; i++) {
if (array2[i][key])
result.push(array2[i]);
}
for (var i = 0; i < array1.length; i++) {
delete array1[i][key];
}
return result;
}
Tất nhiên bạn cần chắc chắn rằng khóa không xuất hiện trước đó, nếu không bạn sẽ phá hủy dữ liệu của mình ...
Tôi sẽ đóng góp với những gì đã làm việc tốt nhất cho tôi:
if (!Array.prototype.intersect){
Array.prototype.intersect = function (arr1) {
var r = [], o = {}, l = this.length, i, v;
for (i = 0; i < l; i++) {
o[this[i]] = true;
}
l = arr1.length;
for (i = 0; i < l; i++) {
v = arr1[i];
if (v in o) {
r.push(v);
}
}
return r;
};
}
"IndexOf" cho IE 9.0, chrome, firefox, opera,
function intersection(a,b){
var rs = [], x = a.length;
while (x--) b.indexOf(a[x])!=-1 && rs.push(a[x]);
return rs.sort();
}
intersection([1,2,3], [2,3,4,5]);
//Result: [2,3]
'use strict'
// Example 1
function intersection(a1, a2) {
return a1.filter(x => a2.indexOf(x) > -1)
}
// Example 2 (prototype function)
Array.prototype.intersection = function(arr) {
return this.filter(x => arr.indexOf(x) > -1)
}
const a1 = [1, 2, 3]
const a2 = [2, 3, 4, 5]
console.log(intersection(a1, a2))
console.log(a1.intersection(a2))
Một cách tiếp cận chức năng phải xem xét chỉ sử dụng các chức năng thuần túy mà không có tác dụng phụ, mỗi chức năng chỉ liên quan đến một công việc duy nhất.
Những hạn chế này tăng cường khả năng kết hợp và tái sử dụng của các chức năng liên quan.
// small, reusable auxiliary functions
const createSet = xs => new Set(xs);
const filter = f => xs => xs.filter(apply(f));
const apply = f => x => f(x);
// intersection
const intersect = xs => ys => {
const zs = createSet(ys);
return filter(x => zs.has(x)
? true
: false
) (xs);
};
// mock data
const xs = [1,2,2,3,4,5];
const ys = [0,1,2,3,3,3,6,7,8,9];
// run it
console.log( intersect(xs) (ys) );
Xin lưu ý rằng Set
loại bản địa được sử dụng, có hiệu suất tra cứu thuận lợi.
Rõ ràng các mục xuất hiện lặp đi lặp lại từ lần đầu tiên Array
được bảo tồn, trong khi mục thứ hai Array
được nhân đôi. Điều này có thể hoặc có thể không phải là hành vi mong muốn. Nếu bạn cần một kết quả duy nhất, chỉ cần áp dụng dedupe
cho đối số đầu tiên:
// auxiliary functions
const apply = f => x => f(x);
const comp = f => g => x => f(g(x));
const afrom = apply(Array.from);
const createSet = xs => new Set(xs);
const filter = f => xs => xs.filter(apply(f));
// intersection
const intersect = xs => ys => {
const zs = createSet(ys);
return filter(x => zs.has(x)
? true
: false
) (xs);
};
// de-duplication
const dedupe = comp(afrom) (createSet);
// mock data
const xs = [1,2,2,3,4,5];
const ys = [0,1,2,3,3,3,6,7,8,9];
// unique result
console.log( intersect(dedupe(xs)) (ys) );
Array
s nàoNếu bạn muốn tính giao điểm của một số Array
s tùy ý chỉ cần soạn intersect
với foldl
. Đây là một chức năng tiện lợi:
// auxiliary functions
const apply = f => x => f(x);
const uncurry = f => (x, y) => f(x) (y);
const createSet = xs => new Set(xs);
const filter = f => xs => xs.filter(apply(f));
const foldl = f => acc => xs => xs.reduce(uncurry(f), acc);
// intersection
const intersect = xs => ys => {
const zs = createSet(ys);
return filter(x => zs.has(x)
? true
: false
) (xs);
};
// intersection of an arbitrarily number of Arrays
const intersectn = (head, ...tail) => foldl(intersect) (head) (tail);
// mock data
const xs = [1,2,2,3,4,5];
const ys = [0,1,2,3,3,3,6,7,8,9];
const zs = [0,1,2,3,4,5,6];
// run
console.log( intersectn(xs, ys, zs) );
(expr ? true : false)
là dư thừa. Sử dụng chỉ expr
khi booleans thực tế không cần thiết, chỉ cần trung thực / giả.
Để đơn giản:
// Usage
const intersection = allLists
.reduce(intersect, allValues)
.reduce(removeDuplicates, []);
// Implementation
const intersect = (intersection, list) =>
intersection.filter(item =>
list.some(x => x === item));
const removeDuplicates = (uniques, item) =>
uniques.includes(item) ? uniques : uniques.concat(item);
// Example Data
const somePeople = [bob, doug, jill];
const otherPeople = [sarah, bob, jill];
const morePeople = [jack, jill];
const allPeople = [...somePeople, ...otherPeople, ...morePeople];
const allGroups = [somePeople, otherPeople, morePeople];
// Example Usage
const intersection = allGroups
.reduce(intersect, allPeople)
.reduce(removeDuplicates, []);
intersection; // [jill]
Những lợi ích:
Hạn chế:
Bạn sẽ không muốn sử dụng công cụ này cho công cụ 3D hoặc kernel, nhưng nếu bạn gặp vấn đề khi chạy ứng dụng này trong một ứng dụng dựa trên sự kiện, thiết kế của bạn có vấn đề lớn hơn.
.reduce
để xây dựng một bản đồ, và .filter
để tìm giao lộ. delete
trong phạm vi .filter
cho phép chúng ta xử lý mảng thứ hai như thể đó là một tập hợp duy nhất.
function intersection (a, b) {
var seen = a.reduce(function (h, k) {
h[k] = true;
return h;
}, {});
return b.filter(function (k) {
var exists = seen[k];
delete seen[k];
return exists;
});
}
Tôi thấy cách tiếp cận này khá dễ dàng để lý do về. Nó thực hiện trong thời gian liên tục.
Đây có lẽ là cách đơn giản nhất, bên cạnh list1.filter (n => list2.includes (n))
var list1 = ['bread', 'ice cream', 'cereals', 'strawberry', 'chocolate']
var list2 = ['bread', 'cherry', 'ice cream', 'oats']
function check_common(list1, list2){
list3 = []
for (let i=0; i<list1.length; i++){
for (let j=0; j<list2.length; j++){
if (list1[i] === list2[j]){
list3.push(list1[i]);
}
}
}
return list3
}
check_common(list1, list2) // ["bread", "ice cream"]
Nếu bạn cần phải có nó xử lý giao nhau nhiều mảng:
const intersect = (a, b, ...rest) => {
if (rest.length === 0) return [...new Set(a)].filter(x => new Set(b).has(x));
return intersect(a, intersect(b, ...rest));
};
console.log(intersect([1,2,3,4,5], [1,2], [1, 2, 3,4,5], [2, 10, 1])) // [1,2]
Phong cách ES6 đơn giản.
const intersection = (a, b) => {
const s = new Set(b);
return a.filter(x => s.has(x));
};
Thí dụ:
intersection([1, 2, 3], [4, 3, 2]); // [2, 3]
Tôi đã viết một hàm intesection thậm chí có thể phát hiện giao điểm của mảng các đối tượng dựa trên thuộc tính cụ thể của các đối tượng đó.
Ví dụ,
if arr1 = [{id: 10}, {id: 20}]
and arr2 = [{id: 20}, {id: 25}]
và chúng tôi muốn giao nhau dựa trên thuộc id
tính, thì đầu ra phải là:
[{id: 20}]
Như vậy, hàm cho cùng (lưu ý: mã ES6) là:
const intersect = (arr1, arr2, accessors = [v => v, v => v]) => {
const [fn1, fn2] = accessors;
const set = new Set(arr2.map(v => fn2(v)));
return arr1.filter(value => set.has(fn1(value)));
};
và bạn có thể gọi hàm là:
intersect(arr1, arr2, [elem => elem.id, elem => elem.id])
Cũng lưu ý: hàm này tìm thấy giao điểm coi mảng đầu tiên là mảng chính và do đó kết quả giao cắt sẽ là của mảng chính.
Hãy nghĩ rằng điều này sẽ nhanh hơn với thời gian O (mảng1 + mảng2) giả sử map.has () là ~ O (1). Xin vui lòng sửa cho tôi nếu sai.
const intersection = (a1, a2) => {
let map = new Map();
let result = []
for (let i of a1) {
if (!map.has(i)) map.set(i, true);
}
for (let i of a2) {
if (map.has(i)) result.push(i)
}
return result;
}
Đây là cách triển khai underscore.js :
_.intersection = function(array) {
if (array == null) return [];
var result = [];
var argsLength = arguments.length;
for (var i = 0, length = array.length; i < length; i++) {
var item = array[i];
if (_.contains(result, item)) continue;
for (var j = 1; j < argsLength; j++) {
if (!_.contains(arguments[j], item)) break;
}
if (j === argsLength) result.push(item);
}
return result;
};
Nguồn: http://underscorejs.org/docs/underscore.html#section-62