คาดว่าอาร์เรย์จะเท่ากับละเว้นคำสั่ง


93

ด้วย Jasmine มีวิธีทดสอบว่า 2 อาร์เรย์มีองค์ประกอบเดียวกันหรือไม่ แต่ไม่จำเป็นต้องอยู่ในลำดับเดียวกัน? กล่าวคือ

array1 = [1,2,3];
array2 = [3,2,1];

expect(array1).toEqualIgnoreOrder(array2);//should be true

24
expect(array1.sort()).toEqual(array2.sort());เหรอ?
raina77ow

@ raina77ow ฉันเดาว่าคงได้ผลเช่นกัน
David กล่าวว่า Reinstate Monica

1
ฉันควรตอบคำถามนี้หรือไม่?
raina77ow

1
@ raina77ow มันซับซ้อนขึ้นเล็กน้อยเมื่อมีอาร์เรย์ของวัตถุ คงจะดีไม่น้อยหากจัสมินมีของนอกกรอบสำหรับสิ่งนี้
David กล่าวว่า Reinstate Monica

2
ฉันไม่พบสิ่งใดที่ยอดเยี่ยมในจัสมินเองดังนั้นจึงแนะนำ lodash (หรือคุณสามารถใช้ขีดล่าง / ไลบรารีคอลเลกชัน js อื่น ๆ ) ในโครงการทดสอบของฉันสำหรับสิ่งต่างๆเช่นนี้
ktharsis

คำตอบ:


65

หากเป็นเพียงจำนวนเต็มหรือค่าดั้งเดิมอื่น ๆ คุณสามารถsort()เปรียบเทียบได้ก่อน

expect(array1.sort()).toEqual(array2.sort());

หากเป็นวัตถุให้รวมเข้ากับmap()ฟังก์ชันเพื่อแยกตัวระบุที่จะนำมาเปรียบเทียบ

array1 = [{id:1}, {id:2}, {id:3}];
array2 = [{id:3}, {id:2}, {id:1}];

expect(array1.map(a => a.id).sort()).toEqual(array2.map(a => a.id).sort());

วิธีการเรียงลำดับอาร์เรย์เริ่มต้นใช้การเปรียบเทียบสตริงสำหรับตัวเลข "10" < "2" === true
Shmiddty

[10, 2, 1].sort() ---> [1, 10, 2]
Shmiddty

9
@Shmiddty ฉันไม่เห็นว่ามันมีความสำคัญอย่างไรในกรณีนี้ ตราบใดที่คำสั่งเหมือนกันสำหรับทั้งสองอาร์เรย์ก็น่าจะใช้ได้
แพนด้าสี

1
จุดยุติธรรม เป็นที่น่าสังเกตว่าsortเกิดขึ้นในสถานที่แม้ว่า (มันกลายพันธุ์ตามที่เรียก)
Shmiddty

1
ส่วนออบเจ็กต์ของคำตอบนี้จะไม่ตรวจสอบว่าวัตถุนั้นตรงกันหรือไม่เนื่องจากเป็นการเปรียบเทียบอาร์เรย์ที่แมปเท่านั้น คุณไม่จำเป็นต้องใช้แผนที่sortใช้ฟังก์ชันเสริมที่สามารถใช้ทำการเปรียบเทียบได้
เนียน

22

ดอกมะลิรุ่น 2.8 ขึ้นไปมี

jasmine.arrayWithExactContents()

ซึ่งคาดว่าอาร์เรย์จะมีองค์ประกอบที่ระบุไว้ทุกประการตามลำดับ

array1 = [1,2,3];
array2 = [3,2,1];
expect(array1).toEqual(jasmine.arrayWithExactContents(array2))

ดูhttps://jasmine.github.io/api/3.4/jasmine.html


13

เรียบง่าย ...

array1 = [1,2,3];
array2 = [3,2,1];

expect(array1).toEqual(jasmine.arrayContaining(array2));

7
คำตอบที่ดี! คุณต้องตรวจสอบด้วยว่าความยาวเท่ากันมิฉะนั้นคุณจะมีผลบวกลวงใน [1,2,3,4] และ [3,2,1]
Kristian Hanekamp

10
// check if every element of array2 is element of array1
// to ensure [1, 1] !== [1, 2]
array2.forEach(x => expect(array1).toContain(x))

// check if every element of array1 is element of array2
// to ensure [1, 2] !== [1, 1]
array1.forEach(x => expect(array2).toContain(x))

// check if they have equal length to ensure [1] !== [1, 1]
expect(array1.length).toBe(array2.length)

2
ใช้.forEachแทน.mapเพื่อประหยัดเวลาและหน่วยความจำมากมาย
Darkhogg

1
น่าเสียดายที่สิ่งนี้จะผ่านไปพร้อมกับอาร์เรย์ต่อไปนี้แม้ว่าจะแตกต่างกัน: array1 = [1, 2],array2 = [1, 1]
redbmk

2
Nice catch @redbmk ฉันได้เพิ่มเช็คสำหรับสิ่งนี้ขอบคุณ!
Jannic Beck

ฉันคิดว่ายังมีปัญหา - จะเกิดอะไรขึ้นถ้าอาร์เรย์เป็น[1,1,2]และ[1,2,2]? อาจจะใช้แผนที่สำหรับแต่ละรายการหรือบางอย่าง? เช่นarray1.reduce((map, item) => { map.set(item, (map.get(item) || 0) + 1)), new Map())สำหรับอาร์เรย์ทั้งสองแล้ววนซ้ำและตรวจสอบว่าจำนวนเงินเท่ากันหรือไม่ ดูเหมือนจะมีการทำซ้ำหลายครั้ง แต่จะต้องละเอียดกว่านี้
redbmk

อาจใช้การยกเว้นจากอาร์เรย์ควบคุม (ลบองค์ประกอบเมื่อพบแล้วตรวจสอบความยาวเป็น 0 ในตอนท้าย) แต่ก็ไม่คุ้มกับความพยายามในกรณีปกติ
lifecoder

10

คุณสามารถใช้ expect.arrayContaining (array) จาก standard jest:

  const expected = ['Alice', 'Bob'];
  it('matches even if received contains additional elements', () => {
    expect(['Alice', 'Bob', 'Eve']).toEqual(expect.arrayContaining(expected));
  });

โซลูชั่นที่สมบูรณ์แบบ! นี่น่าจะเป็นคำตอบที่เลือก ..
rohit_wason

2

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

สำหรับกรณีนี้เราสามารถใช้toIncludeSameMembers

expect([{foo: "bar"}, {baz: "qux"}]).toIncludeSameMembers([{baz: "qux"}, {foo: "bar"}]);

1
//Compare arrays without order
//Example
//a1 = [1, 2, 3, 4, 5]
//a2 = [3, 2, 1, 5, 4]
//isEqual(a1, a2) -> true
//a1 = [1, 2, 3, 4, 5];
//a2 = [3, 2, 1, 5, 4, 6];
//isEqual(a1, a2) -> false


function isInArray(a, e) {
  for ( var i = a.length; i--; ) {
    if ( a[i] === e ) return true;
  }
  return false;
}

function isEqArrays(a1, a2) {
  if ( a1.length !== a2.length ) {
    return false;
  }
  for ( var i = a1.length; i--; ) {
    if ( !isInArray( a2, a1[i] ) ) {
      return false;
    }
  }
  return true;
}

0
function equal(arr1, arr2){
    return arr1.length === arr2.length
    &&
    arr1.every((item)=>{
        return arr2.indexOf(item) >-1
    }) 
    &&
    arr2.every((item)=>{
        return arr1.indexOf(item) >-1
    })
}

แนวคิดต่อไปนี้คือการพิจารณาก่อนว่าความยาวของอาร์เรย์ทั้งสองเท่ากันหรือไม่จากนั้นตรวจสอบว่าองค์ประกอบทั้งหมดอยู่ในอาร์เรย์ของอีกฝ่ายหรือไม่


นี้ไม่ได้คำนึงถึงความถี่ของรายการ: ผลตอบแทนequal([1, 1, 2], [1, 2, 2]) true
MarkMYoung

0

นี่คือวิธีแก้ปัญหาที่ใช้ได้กับหมายเลขหรืออาร์เรย์ใด ๆ

https://gist.github.com/tvler/cc5b2a3f01543e1658b25ca567c078e4

const areUnsortedArraysEqual = (...arrs) =>
  arrs.every((arr, i, [first]) => !i || arr.length === first.length) &&
  arrs
    .map(arr =>
      arr.reduce(
        (map, item) => map.set(item, (map.get(item) || 0) + 1),
        new Map(),
      ),
    )
    .every(
      (map, i, [first]) =>
        !i ||
        [...first, ...map].every(([item]) => first.get(item) === map.get(item)),
    );

การทดสอบบางอย่าง (คำตอบสองสามข้อสำหรับคำถามนี้ไม่ได้พิจารณาถึงอาร์เรย์ที่มีหลายรายการที่มีค่าเดียวกันดังนั้น [1, 2, 2] และ [1, 2] จะส่งคืนค่าจริงอย่างไม่ถูกต้อง)

[1, 2] true
[1, 2], [1, 2] true
[1, 2], [1, 2], [1, 2] true
[1, 2], [2, 1] true
[1, 1, 2], [1, 2, 1] true
[1, 2], [1, 2, 3] false
[1, 2, 3, 4], [1, 2, 3], [1, 2] false
[1, 2, 2], [1, 2] false
[1, 1, 2], [1, 2, 2] false
[1, 2, 3], [1, 2], [1, 2, 3] false

0

อัลกอริทึมนี้เหมาะสำหรับอาร์เรย์ที่แต่ละรายการไม่ซ้ำกัน ถ้าไม่คุณสามารถเพิ่มบางอย่างเพื่อตรวจสอบรายการที่ซ้ำกัน ...

tests = [
  [ [1,0,1] , [0,1,1] ],
  [ [1,0,1] , [0,0,1] ], //breaks on this one...
  [ [2,3,3] , [2,2,3] ], //breaks on this one also...
  [ [1,2,3] , [2,1,3] ],
  [ [2,3,1] , [1,2,2] ],
  [ [2,2,1] , [1,3,2] ]
]

tests.forEach(function(test) {
  console.log('eqArraySets( '+test[0]+' , '+test[1]+' ) = '+eqArraySets( test[0] , test[1] ));
});


function eqArraySets(a, b) {
	if ( a.length !== b.length ) { return false; }
	for ( var i = a.length; i--; ) {
		if ( !(b.indexOf(a[i])>-1) ) { return false; }
		if ( !(a.indexOf(b[i])>-1) ) { return false; }
	}
	return true;
}


0

แนวทางนี้มีประสิทธิภาพในการรันไทม์ที่แย่ที่สุดในทางทฤษฎี แต่เนื่องจากไม่ได้ทำการเขียนใด ๆ บนอาร์เรย์จึงอาจเร็วกว่าในหลาย ๆ สถานการณ์ (ยังไม่ได้ทดสอบประสิทธิภาพ):

คำเตือน: ดังที่ Torben ชี้ให้เห็นในความคิดเห็นวิธีนี้จะใช้ได้ก็ต่อเมื่ออาร์เรย์ทั้งสองมีองค์ประกอบที่ไม่ซ้ำกัน (ไม่ซ้ำกัน) (เช่นเดียวกับคำตอบอื่น ๆ ที่นี่)

/**
 * Determine whether two arrays contain exactly the same elements, independent of order.
 * @see /programming/32103252/expect-arrays-to-be-equal-ignoring-order/48973444#48973444
 */
function cmpIgnoreOrder(a, b) {
  const { every, includes } = _;
  return a.length === b.length && every(a, v => includes(b, v));
}

// the following should be all true!
const results = [
  !!cmpIgnoreOrder([1,2,3], [3,1,2]),
  !!cmpIgnoreOrder([4,1,2,3], [3,4,1,2]),
  !!cmpIgnoreOrder([], []),
  !cmpIgnoreOrder([1,2,3], [3,4,1,2]),
  !cmpIgnoreOrder([1], []),
  !cmpIgnoreOrder([1, 3, 4], [3,4,5])
];

console.log('Results: ', results)
console.assert(_.reduce(results, (a, b) => a && b, true), 'Test did not pass!');
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.js"></script>


1
คุณหมายความว่าอย่างไรเมื่อคุณบอกว่าสร้างสำเนาจำนวนมาก Array#sortเรียงลำดับอาร์เรย์ในสถานที่
philraj

1
ล้มเหลวสำหรับอาร์เรย์เหล่านี้: [1,1,2,3], [3,3,1,2]
Torben Kohlmeier

1
@TorbenKohlmeier ขอบคุณฉันอัปเดตคำตอบของฉัน (ยอมรับความพ่ายแพ้ในเรื่องอาร์เรย์ที่ไม่ซ้ำกัน)
Domi

0

มีตัวจับคู่สำหรับกรณีการใช้งานนี้:

https://github.com/jest-community/jest-extended/pull/122/files

test('passes when arrays match in a different order', () => {
  expect([1, 2, 3]).toMatchArray([3, 1, 2]);
  expect([{ foo: 'bar' }, { baz: 'qux' }]).toMatchArray([{ baz: 'qux' }, { foo: 'bar' }]);
});

แต่นั่นเป็นส่วนหนึ่งjest-extendedกล่าวคือไม่สามารถใช้เป็นฟังก์ชันหลักของ Jest ได้ใช่ไหม?
bluenote10

-1

คุณสามารถใช้สิ่งต่างๆเช่น:

expect(array1).toEqual(jasmine.arrayContaining(array2));

jasmineอย่าลืมนำเข้า หรือเพิ่มลงในไฟล์.eslintrc


-4

Jest มีฟังก์ชันที่เรียกว่าexpect.arrayContainingซึ่งจะทำสิ่งที่คุณต้องการ:

expect(array1).toEqual(expect.arrayContaining(array2))

คุณอาจต้องการตรวจสอบว่ามีความยาวเท่ากันหรือไม่เนื่องจากการทดสอบจะผ่านถ้า

อาร์เรย์ที่คาดไว้เป็นส่วนย่อยของอาร์เรย์ที่ได้รับ

ตามเอกสาร

แก้ไข: ขออภัยที่ฉันไม่สังเกตเห็นแท็กจัสมินนี่เป็นวิธีที่ใช้ได้กับJest

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.