การใช้ Lodash เพื่อเปรียบเทียบอาร์เรย์ (รายการที่มีอยู่โดยไม่มีคำสั่งซื้อ)


126

ฉันรู้ว่าฉันทำได้โดยใช้ลูป แต่ฉันกำลังพยายามหาวิธีที่สวยงามในการทำสิ่งนี้:

ฉันมีสองอาร์เรย์:

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

ฉันต้องการใช้lodashเพื่อยืนยันว่าทั้งสองอาร์เรย์ข้างต้นเหมือนกัน โดย 'เหมือนกัน' หมายความว่าไม่มีรายการarray1ที่ไม่มีอยู่ในarray2.

ในแง่ของการตรวจสอบความเท่าเทียมกันระหว่างรายการเหล่านี้:

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

หรือ

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

ทั้งสองทำงานเนื่องจากตัวอักษรจะเรียงตามลำดับเสมอ

คำตอบ:


224

หากคุณจัดเรียงอาร์เรย์ภายนอกคุณสามารถใช้ได้_.isEqual()เนื่องจากอาร์เรย์ด้านในถูกจัดเรียงเรียบร้อยแล้ว

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

โปรดทราบว่า.sort()จะทำให้อาร์เรย์กลายพันธุ์ หากเป็นปัญหาสำหรับคุณให้ทำสำเนาก่อนโดยใช้ (ตัวอย่าง) .slice()หรือตัวดำเนินการกระจาย ( ...)

หรือทำตามที่ Daniel Budick แนะนำในความคิดเห็นด้านล่าง:

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

Lodash's sortBy()จะไม่กลายพันธุ์อาร์เรย์


6
พิจารณาว่า array.sort () กำลังกลายพันธุ์อาร์เรย์เดิม บางทีอันนี้อาจจะดีกว่า: var array1 = [['a', 'b'], ['b', 'c']]; var array2 = [['b', 'c'], ['a', 'b']]; _.isEqual ([... array1] .sort (), [... array2] .sort ()); // true
Yaniv Efraim

3
เพิ่มสองประโยคที่สังเกตว่า.sort()กลายพันธุ์และแนะนำตัวเลือกสำหรับการคัดลอกก่อนหากเป็นปัญหาสำหรับผู้ใช้
Trott

6
หากคุณใช้ lodash อยู่แล้วคุณสามารถทำได้_.isEqual(_.sortBy(array1), _sortBy(array2))เพื่อป้องกันการกลายพันธุ์
Daniel Budick

1
@DanielBudick ขอบคุณ! ฉันได้เพิ่มคำตอบนั้นแล้ว ข้อเสนอแนะที่ดี
Trott

33

คุณสามารถใช้ lodashs xorสำหรับสิ่งนี้

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

หากคุณคิดว่าอาร์เรย์ [1, 1] แตกต่างจากอาร์เรย์ [1] คุณอาจปรับปรุงประสิทธิภาพได้เล็กน้อยดังนี้:

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

1
ต้องเรียงลำดับอาร์เรย์อยู่ดี
โสวัตถาสก

1
นี่น่าจะเป็นวิธีที่ดีกว่าสำหรับเวอร์ชันใหม่กว่า
Leonardo

@Sovattha Sok อาร์เรย์ไม่จำเป็นต้องเรียงลำดับ การทำ_.xor([3,4], [4,3]).length == 0จะทำให้คุณได้รับความจริง
Nikolay

1
คำเตือน: เทคนิคนี้ใช้ได้ดีกับอาร์เรย์ "ขนาดเล็ก" แต่อาจช่วยลดความเจ็บปวดและช่วยเพิ่มความจำได้หากอาร์เรย์ของคุณมีขนาดใหญ่และส่วนใหญ่จะแตกต่างกันเนื่องจาก _.xor () จะยังคงดำเนินต่อไปเรื่อย ๆ เมื่อผ่านความแตกต่างแรก กล่าวอีกนัยหนึ่งมันไม่ได้กลับมาอย่างรวดเร็วในความแตกต่างแรกที่ตรวจพบ
XDS

6

โดย 'เหมือนกัน' ฉันหมายความว่าไม่มีรายการใดใน array1 ที่ไม่มีอยู่ใน array2

คุณสามารถใช้เรียบ () และความแตกต่าง () สำหรับเรื่องนี้ซึ่งทำงานได้ดีถ้าคุณไม่ดูแลถ้ามีรายการในarray2ที่ไม่ได้array1อยู่ใน ดูเหมือนว่าคุณกำลังถามว่าarray1 เป็นส่วนย่อยของ array2หรือไม่?

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

มีคำตอบอยู่แล้วที่นี่ แต่นี่คือการใช้งาน JS ที่แท้จริงของฉัน ฉันไม่แน่ใจว่าเหมาะสมหรือไม่ แต่แน่ใจว่าโปร่งใสอ่านได้และเรียบง่าย

// 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)

เหตุผลcontains()ก็คือถ้าaมีองค์ประกอบทั้งหมดของbการใส่ไว้ในชุดเดียวกันจะไม่เปลี่ยนขนาด

ตัวอย่างเช่นถ้าconst a = [1,2,3,4]และแล้วconst b = [1,2] ที่คุณสามารถดูชุดส่งผลให้มีองค์ประกอบเช่นเดียวกับnew Set([...a, ...b]) === {1,2,3,4}a

จากนั้นเพื่อให้กระชับมากขึ้นเราสามารถต้มได้ดังต่อไปนี้:

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

1

PURE JS (ใช้งานได้เช่นกันเมื่ออาร์เรย์และ subarrays มีมากกว่า 2 องค์ประกอบที่มีลำดับโดยพลการ) หากสตริงมี,ใช้เป็นjoin('-')อักขระพารามิเตอร์ (สามารถเป็น utf) ซึ่งไม่ได้ใช้ในสตริง

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


0

เราสามารถใช้_.differenceฟังก์ชันเพื่อดูว่ามีความแตกต่างหรือไม่

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

ฉันหวังว่านี่จะช่วยคุณได้


5
ผิดการทำงานของคุณจะได้รับtrueสำหรับconsole.log(isSame([1,2], [2,3,1]));
เดวิดหลิน

3
ขอบคุณ @DavidLin ที่ชี้ให้เห็น ฉันได้ทำการเปลี่ยนแปลงเพื่อพิจารณากรณีนั้น ขอบคุณและขออภัยในความไม่สะดวก
Amitesh

2
คุณไม่จำเป็นต้องเปลี่ยนสถานที่สำหรับ a & b หากความยาวไม่เท่ากัน หากความยาวแตกต่างกันก็จะไม่สามารถเท่ากันได้ดังนั้นหาก (arrayOne.lenght! == arrayTwo.lenght) ส่งคืนเท็จ
Alex

1
-1 จุดในการมีผู้ที่ไม่มีaและbตัวแปร คุณเพียงใช้ตัวแปรเหล่านั้นภายในif-thenส่วนหนึ่งและสิ่งแรกที่คุณทำมีค่าเหล่านั้นทิ้งโหลดที่บรรทัดที่ 2 return arrayOne.length <= arrayTwo.length && _.isEmpty(_.difference(arrayTwo.sort(), arrayTwo.sort());ผมคิดว่าสายเดี่ยวต่อไปนี้จะทำงานเหมือนกัน: และยังสามารถที่จะปรับตัวดีขึ้นเข้า<= ===
Mariano Desanze

1
และ_.differenceจะส่งคืนรายการที่ขาดหายไปของอาร์กิวเมนต์ที่ 1 แต่ไม่หายไปในรายการที่ 2 ดังนั้นนี้ไม่ถูกต้องจะกลับมาtrueเมื่อคุณทำซ้ำรายการในวันที่ 1 ที่ isSame([1, 2, 3], [1, 2, 2])2:
Mariano Desanze

0

แก้ไข: ฉันพลาดแง่มุมหลายมิติของคำถามนี้ดังนั้นฉันจึงทิ้งไว้ที่นี่เผื่อว่าจะช่วยให้ผู้คนเปรียบเทียบอาร์เรย์หนึ่งมิติได้

เป็นคำถามเก่า แต่ฉันมีปัญหาเกี่ยวกับความเร็วในการใช้งาน.sort()หรือsortBy()ฉันจึงใช้สิ่งนี้แทน:

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

มันตั้งใจที่จะล้มเหลวอย่างรวดเร็วและสำหรับจุดประสงค์ของฉันก็ใช้ได้ดี


การตรวจครั้งสุดท้ายจำเป็นจริงหรือ? array1.every((str) => array2.includes(str))ควรจะเพียงพอ นอกจากนี้ OP ต้องการใช้ lodash อย่างน้อยคุณควรพูดว่าทำไมคุณถึงเสนอโซลูชัน vanillaJS (... ตอนนี้เรามีทุกและรวม ... ) โปรดให้ตัวอย่างวิธีใช้ฟังก์ชันของคุณกับปัญหาที่ให้มาด้วย (อาร์เรย์ 2 มิติ)
line-o

นั่นเป็นจุดที่ดี - ฉันไม่ได้พูดถึงแง่มุมหลายมิติไม่ใช่ข้อกำหนดสำหรับ lodash ฉันคิดว่ามันจะมีประโยชน์สำหรับทุกคนที่ค้นหา (เหมือนฉัน) lodash methods to compare arrays without considering orderเพื่อดูทางเลือกอื่นใน Javascript สมัยใหม่ การตรวจสอบครั้งที่สองเป็นสิ่งที่จำเป็นเนื่องจากarraysContainSameStrings(['1', '2', '2'], ['1', '2', '3'])จะคืนค่าจริง ฉันจะทิ้งไว้ที่นี่เพราะมันอาจช่วยได้ แต่ฉันขอขอบคุณที่ยังไม่ได้ตอบคำถาม
charliematters
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.