รหัสที่ง่ายที่สุดและไม่มีไลบรารีสำหรับการใช้งานการแยกอาร์เรย์ใน javascript คืออะไร ฉันต้องการเขียน
intersection([1,2,3], [2,3,4,5])
และรับ
[2, 3]
break
เพื่อSimple js loops
เพิ่ม ops / วินาทีถึง ~ 10M
รหัสที่ง่ายที่สุดและไม่มีไลบรารีสำหรับการใช้งานการแยกอาร์เรย์ใน javascript คืออะไร ฉันต้องการเขียน
intersection([1,2,3], [2,3,4,5])
และรับ
[2, 3]
break
เพื่อSimple js loops
เพิ่ม ops / วินาทีถึง ~ 10M
คำตอบ:
ใช้การรวมกันของArray.prototype.filter
และArray.prototype.indexOf
:
array1.filter(value => -1 !== array2.indexOf(value))
หรือตามที่vrugtehagelแนะนำไว้ในความคิดเห็นคุณสามารถใช้Array.prototype.includes
รหัสล่าสุดได้ง่ายขึ้น:
array1.filter(value => array2.includes(value))
สำหรับเบราว์เซอร์รุ่นเก่า:
array1.filter(function(n) {
return array2.indexOf(n) !== -1;
});
intersection([1,2,1,1,3], [1])
[1, 1, 1]
ผลตอบแทน มันควรจะกลับมา[1]
ไหม?
array2.indexOf(n) != -1
เป็นหนึ่งสามารถเขียนarray2.includes(n)
รหัสได้ง่ายขึ้น
การทำลายล้างดูเหมือนง่ายที่สุดโดยเฉพาะอย่างยิ่งถ้าเราสามารถสมมติว่าอินพุตถูกเรียงลำดับ:
/* 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;
}
การไม่ทำลายจะต้องมีผมที่ซับซ้อนมากขึ้นเนื่องจากเราต้องติดตามดัชนี:
/* 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
เป็นคุณสมบัติในอาร์เรย์ไม่ใช่วิธีการ มีตัวแปร undelared เป็นในi
result.push(a[i]);
ในที่สุดสิ่งนี้ก็ไม่ได้ผลในกรณีทั่วไป: วัตถุสองชิ้นที่ไม่ได้ใหญ่กว่าวัตถุอื่นตามตัว>
ดำเนินการไม่จำเป็นต้องเท่ากัน intersect_safe( [ {} ], [ {} ] )
ตัวอย่างเช่นจะให้ (เมื่อข้อผิดพลาดที่กล่าวถึงก่อนหน้านี้ได้รับการแก้ไข) อาร์เรย์ที่มีองค์ประกอบหนึ่งซึ่งผิดอย่างชัดเจน
.slice(0)
เพื่อสร้างโคลนของอาร์เรย์ในintersect_safe
แทนที่จะติดตามดัชนี
หากสภาพแวดล้อมของคุณรองรับECMAScript 6 Setวิธีหนึ่งที่ง่ายและมีประสิทธิภาพตามที่คาดคะเน (ดูลิงค์ข้อมูลจำเพาะ):
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);
}
สั้นลง แต่อ่านได้น้อยลง (เช่นกันโดยไม่ต้องสร้างทางแยกเพิ่มเติมSet
):
function intersect(a, b) {
return [...new Set(a)].filter(x => new Set(b).has(x));
}
หลีกเลี่ยงการใหม่Set
จากb
ทุกครั้ง:
function intersect(a, b) {
var setB = new Set(b);
return [...new Set(a)].filter(x => setB.has(x));
}
หมายเหตุว่าเมื่อใช้ชุดคุณจะได้รับค่าที่แตกต่างกันดังนั้นการประเมินnew Set[1,2,3,3].size
3
[...setA]
ไวยากรณ์นี้คืออะไร มีการใช้งานจาวาสคริปต์แบบพิเศษไหม?
x => new Set(b).has(x)
ฟังก์ชั่นลูกศรนั้นไม่เปลี่ยนb
เป็นชุดทุกครั้งที่ถูกประมวลผลหรือ คุณควรบันทึกชุดนั้นในตัวแปร
ใช้ Underscore.jsหรือlodash.js
_.intersection( [0,345,324] , [1,0,324] ) // gives [0,324]
การมีส่วนร่วมของฉันในข้อกำหนด ES6 โดยทั่วไปแล้วจะพบจุดตัดของอาร์เรย์ที่มีจำนวนอาร์เรย์ที่ไม่ จำกัด ที่ระบุไว้เป็นอาร์กิวเมนต์
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]]
แล้วนำ.reduce()
ไปใช้ [0,1,2,3,4,5,6,7,8,9].filter( e => [0,2,4,6,8].includes(e)
การดำเนินการครั้งแรกจะดำเนินการและผลลัพธ์จะกลายเป็นใหม่p
และc
จะกลายเป็น[4,5,6,7]
ในเทิร์นถัดไปและดำเนินการต่อไปเรื่อย ๆ จนกว่าจะไม่มีc
เหลืออีก
prototype
ไม่จำเป็น
// 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]));
ฉันขอแนะนำวิธีแก้ปัญหาสั้น ๆ ข้างต้นซึ่งมีประสิทธิภาพสูงกว่าการใช้งานอื่น ๆ ในอินพุตขนาดใหญ่ หากประสิทธิภาพของอินพุตขนาดเล็กมีความสำคัญให้ตรวจสอบตัวเลือกด้านล่าง
ทางเลือกและการเปรียบเทียบประสิทธิภาพ:
ดูตัวอย่างต่อไปนี้สำหรับการใช้งานทางเลือกและตรวจสอบhttps://jsperf.com/array-intersection-comparisonสำหรับการเปรียบเทียบประสิทธิภาพ
ผลลัพธ์ใน Firefox 53:
Ops / วินาทีในอาร์เรย์ขนาดใหญ่ (10,000 องค์ประกอบ):
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 / วินาทีในอาร์เรย์ขนาดเล็ก (100 องค์ประกอบ):
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])
[2, 2, 3]
ผลตอบแทน
a.filter(b.includes)
ความพยายาม ควรรันเร็วกว่ามาก (เหมือนกับการอัพเกรดฟังก์ชั่นของคุณ)
ลองใช้อาเรย์แบบเชื่อมโยงกันล่ะ?
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;
}
แก้ไข:
// 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;
แทนd[b[j]] = true;
( i
ไม่ได้j
) แต่การแก้ไขต้องใช้ 6 ตัวอักษร
บางอย่างเช่นนี้ไม่ผ่านการทดสอบอย่างดี
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: อัลกอริทึมที่ออกแบบมาสำหรับตัวเลขและสายอักขระปกติการตัดกันของวัตถุอาร์เรย์อาจไม่ทำงาน
ประสิทธิภาพของการนำไปใช้ของ @ atk สำหรับอาร์เรย์ที่เรียงลำดับของดั้งเดิมสามารถปรับปรุงได้โดยใช้. pop แทนที่จะเป็น. 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;
}
ฉันสร้างมาตรฐานการใช้ jsPerf: http://bit.ly/P9FrZK มันเร็วกว่าการใช้. pop ประมาณสามเท่า
a[aLast] > b[bLast]
ด้วยa[aLast].localeCompare(b[bLast]) > 0
(และเหมือนกันกับelse if
ด้านล่าง) สิ่งนี้จะทำงานกับสตริง
.pop
เป็น O (1) และ.shift()
เป็น O (n)
ใช้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);
แต่ฉันจะไม่แนะนำให้ใช้ jQuery สำหรับการจัดการอาเรย์แบบนี้เนื่องจากเอกสารระบุว่าใช้งานได้กับองค์ประกอบเท่านั้น
สำหรับอาร์เรย์ที่มีสตริงหรือตัวเลขเท่านั้นคุณสามารถทำอะไรบางอย่างกับการเรียงลำดับตามคำตอบอื่น ๆ สำหรับกรณีทั่วไปของอาร์เรย์ของวัตถุใด ๆ ฉันไม่คิดว่าคุณสามารถหลีกเลี่ยงได้ในระยะยาว ต่อไปนี้จะให้จุดตัดของอาร์เรย์ใด ๆ ที่ระบุเป็นพารามิเตอร์เพื่อ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
หรือfirstArray
ไม่และไม่ได้อัปเดตข้อมูลอ้างอิงทั้งหมด แก้ไขแล้ว.
มันค่อนข้างสั้นโดยใช้ ES2015 และเซต ยอมรับค่า Array like เช่น String และลบค่าที่ซ้ำกัน
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(''));
คุณสามารถใช้Set
เป็นthisArg
ของArray#filter
และใช้Set#has
เป็นโทรกลับ
function intersection(a, b) {
return a.filter(Set.prototype.has, new Set(b));
}
console.log(intersection([1, 2, 3], [2, 3, 4, 5]));
การปรับแต่งเล็ก ๆ ให้เล็กที่สุดที่นี่ ( ตัวกรอง / indexOf ) คือการสร้างดัชนีของค่าในหนึ่งในอาร์เรย์โดยใช้วัตถุ JavaScript จะลดลงจาก O (N * M) เป็นเวลาเชิงเส้น "คงที่" source1 source2
function intersect(a, b) {
var aa = {};
a.forEach(function(v) { aa[v]=1; });
return b.filter(function(v) { return v in aa; });
}
นี่ไม่ใช่วิธีแก้ปัญหาที่ง่ายที่สุด (มันเป็นรหัสมากกว่าตัวกรอง + indexOf ) และไม่ใช่วิธีที่เร็วที่สุด (อาจช้ากว่าโดยปัจจัยคงที่มากกว่าintersect_safe () ) แต่ดูเหมือนว่าจะมีความสมดุลที่ดี มันอยู่ในด้านที่ง่ายมากในขณะที่ให้ประสิทธิภาพที่ดีและไม่จำเป็นต้องมีอินพุตที่จัดเรียงไว้ล่วงหน้า
อีกวิธีการจัดทำดัชนีสามารถประมวลผลจำนวนอาร์เรย์ในครั้งเดียว:
// 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;
};
มันทำงานได้เฉพาะกับค่าที่สามารถประเมินเป็นสตริงและคุณควรผ่านพวกเขาเป็นอาร์เรย์เช่น:
intersect ([arr1, arr2, arr3...]);
... แต่มันยอมรับวัตถุอย่างโปร่งใสว่าเป็นพารามิเตอร์หรือเป็นองค์ประกอบใด ๆ ที่จะถูกตัดกัน ตัวอย่าง:
intersect ({foo: [1, 2, 3, 4], bar: {a: 2, j:4}}); // [2, 4]
intersect ([{x: "hello", y: "world"}, ["hello", "user"]]); // ["hello"]
แก้ไข:ฉันเพิ่งสังเกตเห็นว่านี่เป็นวิธีที่บั๊กเล็กน้อย
นั่นคือ: ฉันเขียนโค้ดโดยคิดว่าอาร์เรย์อินพุตไม่สามารถมีการทำซ้ำได้เอง (ตามตัวอย่างที่ให้มา)
แต่ถ้าอาร์เรย์อินพุทเกิดขึ้นจะมีการทำซ้ำซึ่งจะให้ผลลัพธ์ที่ผิด ตัวอย่าง (ใช้การใช้งานด้านล่าง):
intersect ([[1, 3, 4, 6, 3], [1, 8, 99]]);
// Expected: [ '1' ]
// Actual: [ '1', '3' ]
โชคดีที่เรื่องนี้แก้ไขได้ง่ายเพียงเพิ่มการทำดัชนีระดับที่สอง นั่นคือ:
เปลี่ยนแปลง:
if (index[v] === undefined) index[v] = 0;
index[v]++;
โดย:
if (index[v] === undefined) index[v] = {};
index[v][i] = true; // Mark as present in i input.
...และ:
if (index[i] == arrLength) retv.push(i);
โดย:
if (Object.keys(index[i]).length == arrLength) retv.push(i);
ตัวอย่างที่สมบูรณ์:
// 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 =
เพิ่มบรรทัดif (typeof v == 'function') continue;
แล้วมันจะข้ามการเพิ่มฟังก์ชั่นไปยังผลลัพธ์ ขอบคุณ!
if (typeof v == 'function')
แล้วเราสามารถใช้ stringification ( v.toString()
) เป็นกุญแจสำหรับดัชนีได้ แต่เราต้องทำอะไรบางอย่างเพื่อรักษามันไว้ วิธีที่ง่ายที่สุดที่จะทำคือเพียงแค่กำหนดฟังก์ชั่นเดิมเป็นค่าแทนของมูลค่าที่แท้จริงที่เรียบง่ายแบบบูล แต่ในกรณีที่ deindexaton ล่าสุดควรจะยังมีการเปลี่ยนแปลงในการตรวจสอบสภาพนี้และเรียกคืนมูลค่าที่เหมาะสม (ฟังก์ชั่น)..
คุณสามารถใช้ (สำหรับเบราว์เซอร์ทั้งหมดยกเว้น IE):
const intersection = array1.filter(element => array2.includes(element));
หรือสำหรับ IE:
const intersection = array1.filter(element => array2.indexOf(element) !== -1);
function intersection(A,B){
var result = new Array();
for (i=0; i<A.length; i++) {
for (j=0; j<B.length; j++) {
if (A[i] == B[j] && $.inArray(A[i],result) == -1) {
result.push(A[i]);
}
}
}
return result;
}
ด้วยข้อ จำกัด บางประการเกี่ยวกับข้อมูลของคุณคุณสามารถทำได้ในเวลาเชิงเส้น !
สำหรับจำนวนเต็มบวก : ใช้การจับคู่อาร์เรย์กับค่าบูลีน "เห็น / ไม่เห็น"
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;
}
มีเทคนิคที่คล้ายกันสำหรับวัตถุ : ใช้คีย์จำลองตั้งค่าเป็น "จริง" สำหรับแต่ละองค์ประกอบในอาร์เรย์ 1 จากนั้นมองหาคีย์นี้ในองค์ประกอบของอาร์เรย์ 2 ทำความสะอาดเมื่อคุณทำเสร็จแล้ว
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;
}
แน่นอนคุณต้องแน่ใจว่ากุญแจไม่เคยปรากฏมาก่อนมิฉะนั้นคุณจะทำลายข้อมูลของคุณ ...
ฉันจะสนับสนุนสิ่งที่ได้ผลดีที่สุดสำหรับฉัน:
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" สำหรับ 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))
วิธีการทำงานจะต้องพิจารณาการใช้ฟังก์ชั่นบริสุทธิ์เท่านั้นโดยไม่มีผลข้างเคียงซึ่งแต่ละอย่างเกี่ยวข้องกับงานเดียวเท่านั้น
ข้อ จำกัด เหล่านี้ช่วยเพิ่มความสามารถในการจัดองค์ประกอบและนำกลับมาใช้ใหม่ของฟังก์ชั่นที่เกี่ยวข้อง
// 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) );
โปรดทราบว่าSet
มีการใช้งานประเภทเนทีฟซึ่งมีประสิทธิภาพการค้นหาที่ได้เปรียบ
เห็นได้ชัดว่ารายการที่เกิดขึ้นซ้ำ ๆ จากครั้งแรกArray
จะถูกเก็บรักษาไว้ในขณะที่รายการที่สองArray
ถูกทำซ้ำ นี่อาจเป็นหรืออาจไม่ใช่พฤติกรรมที่ต้องการ หากคุณต้องการผลลัพธ์ที่ไม่ซ้ำเพียงแค่ใช้dedupe
กับอาร์กิวเมนต์แรก:
// 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 ใด ๆหากคุณต้องการที่จะคำนวณจุดตัดของจำนวนพลของArray
แค่เขียนด้วยintersect
foldl
นี่คือฟังก์ชั่นความสะดวกสบาย:
// 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)
คือซ้ำซ้อน ใช้ในexpr
กรณีที่ไม่จำเป็นต้องใช้บูลีนจริงเพียงแค่ความจริง / เท็จ
เพื่อความเรียบง่าย:
// 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]
ประโยชน์ที่ได้รับ:
ข้อเสีย:
คุณไม่ต้องการใช้สิ่งนี้สำหรับเอ็นจิ้น 3D หรือเคอร์เนล แต่ถ้าคุณมีปัญหาในการทำให้มันทำงานในแอพที่อ้างอิงเหตุการณ์การออกแบบของคุณมีปัญหามากขึ้น
.reduce
เพื่อสร้างแผนที่และ.filter
ค้นหาจุดตัด delete
ภายใน.filter
ช่วยให้เราปฏิบัติต่ออาร์เรย์ที่สองราวกับว่าเป็นชุดที่ไม่ซ้ำกัน
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;
});
}
ฉันพบว่าวิธีนี้ค่อนข้างง่ายที่จะให้เหตุผล มันทำงานในเวลาคงที่
นี่อาจเป็นวิธีที่ง่ายที่สุดนอกเหนือจาก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"]
หากคุณต้องการให้มันจัดการกับการตัดกันหลาย ๆ อาร์เรย์:
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]
วิธีง่ายๆสไตล์ ES6
const intersection = (a, b) => {
const s = new Set(b);
return a.filter(x => s.has(x));
};
ตัวอย่าง:
intersection([1, 2, 3], [4, 3, 2]); // [2, 3]
ฉันได้เขียนฟังก์ชัน intesection ซึ่งสามารถตรวจจับการแยกอาร์เรย์ของวัตถุตามคุณสมบัติเฉพาะของวัตถุเหล่านั้นได้
ตัวอย่างเช่น
if arr1 = [{id: 10}, {id: 20}]
and arr2 = [{id: 20}, {id: 25}]
และเราต้องการจุดตัดตามid
คุณสมบัติจากนั้นผลลัพธ์ควรเป็น:
[{id: 20}]
ดังนั้นฟังก์ชั่นสำหรับรหัสเดียวกัน (หมายเหตุ: รหัส ES6) คือ:
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)));
};
และคุณสามารถเรียกใช้ฟังก์ชันเป็น:
intersect(arr1, arr2, [elem => elem.id, elem => elem.id])
หมายเหตุ: ฟังก์ชั่นนี้ค้นหาจุดตัดที่พิจารณาว่าอาร์เรย์แรกเป็นอาร์เรย์หลักและผลลัพธ์ของการแยกจะเป็นของอาร์เรย์หลัก
คิดว่าสิ่งนี้จะเร็วขึ้นด้วย O (array1 + array2) เวลาที่สมมติว่า map.has () คือ ~ O (1) โปรดแก้ไขให้ฉันถ้าผิด
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;
}
นี่คือการดำเนินการ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;
};
แหล่งที่มา: http://underscorejs.org/docs/underscore.html#section-62