Welcome, One common challenge developers face is comparing arrays—specifically, determining if two arrays contain the same contents, regardless of the order of those contents. This task might seem straightforward at first glance, but it quickly delves into complexities. In this blog post, we’ll discuss various methods, from the simple and direct to the more sophisticated and efficient. Basics This is for Beginners, in JavaScript, comparing two arrays with equality operators simply does not work. [] == [] // false [] === [] // false Comparing Two Arrays Let us begin with regular array comparisons. function arraysEqual(a, b) { if (a === b) return true; if (a == null || b == null) return false; if (a.length !== b.length) return false; for (let i = 0; i < a.length; i++) { if (a[i] !== b[i]) return false; } return true; } // Example usage: const array1 = [1, 2, 3]; const array2 = [1, 2, 3]; const array3 = [1, 2, 4]; arraysEqual(array1, array2); // true arraysEqual(array1, array3); // false Level 1 Our arraysEqual function works for regular array comparisons but not for different orders. const array1 = [1, 2, 3]; const array2 = [2, 3, 1]; arraysEqual(array1, array2); // false Let's change it to work for different ordered arrays. We can do this by simply sort the given arrays before comparison. function arraysEqual(a, b) { a.sort(); b.sort(); if (a === b) return true; if (a == null || b == null) return false; if (a.length !== b.length) return false; for (let i = 0; i < a.length; i++) { if (a[i] !== b[i]) return false; } return true; } Now, our function works well with different-ordered arrays. const array1 = [1, 2, 3]; const array2 = [2, 3, 1]; arraysEqual(array1, array2); // true Level 2 Now, we test the arraysEqual function by giving mixed types of values. arraysEqual(['1', 1], [1, '1']); // false As you can see, our function failed even with the two arrays containing the same values. Let's fix this. function compareMixedTypes(a, b) { if (typeof a === typeof b) { return a === b ? 0 : a < b ? -1 : 1; } return typeof a < typeof b ? -1 : 1; } function arraysEqual(a, b) { a.sort(compareMixedTypes); b.sort(compareMixedTypes); if (a === b) return true; if (a == null || b == null) return false; if (a.length !== b.length) return false; for (let i = 0; i < a.length; i++) { if (a[i] !== b[i]) return false; } return true; } arraysEqual(['1', 1], [1, '1']); // true Level 3 Let's test the arraysEqual function with an array of objects. const a = [{a: 1}, {b: 2}]; const b = [{b: 2}, {a: 1}]; arraysEqual(a, b); // false As you can see, our function failed because the sorting does work for primitives but simply not for objects. Let's remove sorting and try a different method. function inArray(array, el) { for (var i = array.length; i--; ) { if ( array[i] === el ) return true; } return false; } function arraysEqual(a, b) { if (a === b) return true; if (a == null || b == null) return false; if (a.length !== b.length) return false; for (var i = a.length; i--; ) { if (!inArray(b, a[i])) { return false; } } return true; } Let's test again. const array1 = [1, 2, 3]; const array2 = [2, 3, 1]; arraysEqual(array1, array2); // true arraysEqual(['1', 1], [1, '1']); // true arraysEqual([1, 1, 2, 2], [1, 2, 1, 2]); // true const a = [{a: 1}, {b: 2}]; const b = [{b: 2}, {a: 1}]; arraysEqual(a, b); // false As you can see the modified function works for primitives but not for objects, let's fix it in the next level. Level 4 The problem with the inArray function is that we are comparing two values using === operator; we need to find a way to compare objects also with deep nested. We can use the popular lodash library's isEqual function here. Let's change it. function inArray(array, el) { for (var i = array.length; i--; ) { if (_.isEqual(array[i], el)) return true; } return false; } Now, let's try it. let a = [{a: 1}, {b: 2}]; let b = [{b: 2}, {a: 1}]; arraysEqual(a, b); // true a = [{a: {b: {c: ['a', 'b', 'c']}}}, [1, 2, 3]]; b = [[1, 2, 3], {a: {b: {c: ['a', 'b', 'c']}}}]; arraysEqual(a, b); // true Level 5 Now what? If our code is working fine for all cases, then why do we need another level here? There are some problems in the _.isEqual function. https://github.com/lodash/lodash/issues/5401 https://github.com/lodash/lodash/issues/3640 https://github.com/lodash/lodash/issues/3428 Let's verify it now. const a = [{m: new Map([['x', 'y']])}] const b = [{m: new Map([['y', 'x']])}] arraysEqual(a, b); // true console.log(a, b); /* [ { m: Map(1) { 'x' => 'y' } } ] [ { m: Map(1) { 'y' => 'x' } } ] */ So, what is next? Let me introduce our organization's Standard Library function isEqlArr here. import { isEqlArr, shuffle } from '@opentf/std'; let a = [1, 2, 3]; let b = [2, 3, 1]; isEqlArr(a, b); // true a = ['1', 1]; b = [1, '1']; isEqlArr(a, b); // true a = [1, 1, 2, 2]; b = [1, 2, 1, 2]; isEqlArr(a, b); // true a = 'Apple'.split('') b = shuffle('Apple') isEqlArr(a, b); // true a = [{a: 1}, {b: 2}]; b = [{b: 2}, {a: 1}]; isEqlArr(a, b); // true a = [{a: {b: {c: ['a', 'b', 'c']}}}, [1, 2, 3]]; b = [[1, 2, 3], {a: {b: {c: ['a', 'b', 'c']}}}]; isEqlArr(a, b); // true a = [{m: new Map([['x', 'y']])}] b = [{m: new Map([['y', 'x']])}] isEqlArr(a, b); // false Example: Real-World Use Case In this example, we are going to find out how many sets of the same products were in the invoices of a company. Note: If it doesn't make sense, just ignore this example. import { isEqlArr } from '@opentf/std'; const invoices = [ { id: 'c2607dc9-bd74-446d-ac83-de201d158b87', products: [ { id: '4e5fe7a0-0fd2-44f3-bdcd-6a3b2eea4b50', name: 'Product A' }, { id: '863cb499-1943-473b-85f2-285ed9128c74', name: 'Product B' } ] }, { id: '6e523056-1601-41ba-b89e-6ae41164a843', products: [ { id: '4e5fe7a0-0fd2-44f3-bdcd-6a3b2eea4b50', name: 'Product A' }, { id: '401cc691-92f1-4e9e-bd78-995cb9663c5e', name: 'Product C' }, ] }, { id: '3d375953-4c60-433c-b8c2-c45628d8f2d6', products: [ { id: '863cb499-1943-473b-85f2-285ed9128c74', name: 'Product B' }, { id: '4e5fe7a0-0fd2-44f3-bdcd-6a3b2eea4b50', name: 'Product A' } ] } ] let count = 0 for (let i = 0; i < invoices.length; i += 1) { for (let j = 0; j < invoices.length; j += 1) { if (i !== j) { if (isEqlArr(invoices[i].products, invoices[j].products)) { count++ } } } } console.log(count); // 2 Note: You can try out these examples on our online Node.js REPL Conclusion Here, we have seen various levels in comparing arrays of elements unordered. The new Standard library function is used to achieve the same for the following reasons: Cross-Environment Compatibility: Execute seamlessly in browsers, Node.js, Bun, Deno, etc. TypeScript Support Works with both CJS & ESM Supports some Older Browsers & Node.js >= 16 If you need to find out the performance of the lib, please check out these benchmarks. Please don't forget to check out our important Articles: Introducing Our New JavaScript Standard Library You Don’t Need JavaScript Native Methods! Happy coding! 🚀 🙏 Thanks for reading. References: https://stackoverflow.com/questions/29672847/how-to-compare-contents-of-javascript-array-but-not-the-order-of-them https://stackoverflow.com/questions/3243275/javascript-arrays-checking-two-arrays-of-objects-for-same-contents-ignoring-o https://stackoverflow.com/questions/47072055/how-to-make-a-deep-comparison-of-unordered-arrays?noredirect=1&lq=1 https://stackoverflow.com/questions/7837456/how-to-compare-arrays-in-javascript Welcome, One common challenge developers face is comparing arrays—specifically, determining if two arrays contain the same contents, regardless of the order of those contents. This task might seem straightforward at first glance, but it quickly delves into complexities. In this blog post, we’ll discuss various methods, from the simple and direct to the more sophisticated and efficient. Basics This is for Beginners, in JavaScript, comparing two arrays with equality operators simply does not work. [] == [] // false [] === [] // false [] == [] // false [] === [] // false Comparing Two Arrays Let us begin with regular array comparisons. function arraysEqual(a, b) { if (a === b) return true; if (a == null || b == null) return false; if (a.length !== b.length) return false; for (let i = 0; i < a.length; i++) { if (a[i] !== b[i]) return false; } return true; } // Example usage: const array1 = [1, 2, 3]; const array2 = [1, 2, 3]; const array3 = [1, 2, 4]; arraysEqual(array1, array2); // true arraysEqual(array1, array3); // false function arraysEqual(a, b) { if (a === b) return true; if (a == null || b == null) return false; if (a.length !== b.length) return false; for (let i = 0; i < a.length; i++) { if (a[i] !== b[i]) return false; } return true; } // Example usage: const array1 = [1, 2, 3]; const array2 = [1, 2, 3]; const array3 = [1, 2, 4]; arraysEqual(array1, array2); // true arraysEqual(array1, array3); // false Level 1 Our arraysEqual function works for regular array comparisons but not for different orders. arraysEqual const array1 = [1, 2, 3]; const array2 = [2, 3, 1]; arraysEqual(array1, array2); // false const array1 = [1, 2, 3]; const array2 = [2, 3, 1]; arraysEqual(array1, array2); // false Let's change it to work for different ordered arrays. We can do this by simply sort the given arrays before comparison. sort function arraysEqual(a, b) { a.sort(); b.sort(); if (a === b) return true; if (a == null || b == null) return false; if (a.length !== b.length) return false; for (let i = 0; i < a.length; i++) { if (a[i] !== b[i]) return false; } return true; } function arraysEqual(a, b) { a.sort(); b.sort(); if (a === b) return true; if (a == null || b == null) return false; if (a.length !== b.length) return false; for (let i = 0; i < a.length; i++) { if (a[i] !== b[i]) return false; } return true; } Now, our function works well with different-ordered arrays. const array1 = [1, 2, 3]; const array2 = [2, 3, 1]; arraysEqual(array1, array2); // true const array1 = [1, 2, 3]; const array2 = [2, 3, 1]; arraysEqual(array1, array2); // true Level 2 Now, we test the arraysEqual function by giving mixed types of values. arraysEqual arraysEqual(['1', 1], [1, '1']); // false arraysEqual(['1', 1], [1, '1']); // false As you can see, our function failed even with the two arrays containing the same values. failed Let's fix this. function compareMixedTypes(a, b) { if (typeof a === typeof b) { return a === b ? 0 : a < b ? -1 : 1; } return typeof a < typeof b ? -1 : 1; } function arraysEqual(a, b) { a.sort(compareMixedTypes); b.sort(compareMixedTypes); if (a === b) return true; if (a == null || b == null) return false; if (a.length !== b.length) return false; for (let i = 0; i < a.length; i++) { if (a[i] !== b[i]) return false; } return true; } arraysEqual(['1', 1], [1, '1']); // true function compareMixedTypes(a, b) { if (typeof a === typeof b) { return a === b ? 0 : a < b ? -1 : 1; } return typeof a < typeof b ? -1 : 1; } function arraysEqual(a, b) { a.sort(compareMixedTypes); b.sort(compareMixedTypes); if (a === b) return true; if (a == null || b == null) return false; if (a.length !== b.length) return false; for (let i = 0; i < a.length; i++) { if (a[i] !== b[i]) return false; } return true; } arraysEqual(['1', 1], [1, '1']); // true Level 3 Let's test the arraysEqual function with an array of objects. arraysEqual const a = [{a: 1}, {b: 2}]; const b = [{b: 2}, {a: 1}]; arraysEqual(a, b); // false const a = [{a: 1}, {b: 2}]; const b = [{b: 2}, {a: 1}]; arraysEqual(a, b); // false As you can see, our function failed because the sorting does work for primitives but simply not for objects . failed sorting primitives objects Let's remove sorting and try a different method. sorting function inArray(array, el) { for (var i = array.length; i--; ) { if ( array[i] === el ) return true; } return false; } function arraysEqual(a, b) { if (a === b) return true; if (a == null || b == null) return false; if (a.length !== b.length) return false; for (var i = a.length; i--; ) { if (!inArray(b, a[i])) { return false; } } return true; } function inArray(array, el) { for (var i = array.length; i--; ) { if ( array[i] === el ) return true; } return false; } function arraysEqual(a, b) { if (a === b) return true; if (a == null || b == null) return false; if (a.length !== b.length) return false; for (var i = a.length; i--; ) { if (!inArray(b, a[i])) { return false; } } return true; } Let's test again. const array1 = [1, 2, 3]; const array2 = [2, 3, 1]; arraysEqual(array1, array2); // true arraysEqual(['1', 1], [1, '1']); // true arraysEqual([1, 1, 2, 2], [1, 2, 1, 2]); // true const a = [{a: 1}, {b: 2}]; const b = [{b: 2}, {a: 1}]; arraysEqual(a, b); // false const array1 = [1, 2, 3]; const array2 = [2, 3, 1]; arraysEqual(array1, array2); // true arraysEqual(['1', 1], [1, '1']); // true arraysEqual([1, 1, 2, 2], [1, 2, 1, 2]); // true const a = [{a: 1}, {b: 2}]; const b = [{b: 2}, {a: 1}]; arraysEqual(a, b); // false As you can see the modified function works for primitives but not for objects , let's fix it in the next level. primitives objects Level 4 The problem with the inArray function is that we are comparing two values using === operator; we need to find a way to compare objects also with deep nested . inArray === objects deep nested We can use the popular lodash library's isEqual function here. Let's change it. lodash isEqual function inArray(array, el) { for (var i = array.length; i--; ) { if (_.isEqual(array[i], el)) return true; } return false; } function inArray(array, el) { for (var i = array.length; i--; ) { if (_.isEqual(array[i], el)) return true; } return false; } Now, let's try it. let a = [{a: 1}, {b: 2}]; let b = [{b: 2}, {a: 1}]; arraysEqual(a, b); // true a = [{a: {b: {c: ['a', 'b', 'c']}}}, [1, 2, 3]]; b = [[1, 2, 3], {a: {b: {c: ['a', 'b', 'c']}}}]; arraysEqual(a, b); // true let a = [{a: 1}, {b: 2}]; let b = [{b: 2}, {a: 1}]; arraysEqual(a, b); // true a = [{a: {b: {c: ['a', 'b', 'c']}}}, [1, 2, 3]]; b = [[1, 2, 3], {a: {b: {c: ['a', 'b', 'c']}}}]; arraysEqual(a, b); // true Level 5 Now what? If our code is working fine for all cases, then why do we need another level here? There are some problems in the _.isEqual function. _.isEqual https://github.com/lodash/lodash/issues/5401 https://github.com/lodash/lodash/issues/5401 https://github.com/lodash/lodash/issues/3640 https://github.com/lodash/lodash/issues/3640 https://github.com/lodash/lodash/issues/3428 https://github.com/lodash/lodash/issues/3428 Let's verify it now. const a = [{m: new Map([['x', 'y']])}] const b = [{m: new Map([['y', 'x']])}] arraysEqual(a, b); // true console.log(a, b); /* [ { m: Map(1) { 'x' => 'y' } } ] [ { m: Map(1) { 'y' => 'x' } } ] */ const a = [{m: new Map([['x', 'y']])}] const b = [{m: new Map([['y', 'x']])}] arraysEqual(a, b); // true console.log(a, b); /* [ { m: Map(1) { 'x' => 'y' } } ] [ { m: Map(1) { 'y' => 'x' } } ] */ So, what is next? Let me introduce our organization's Standard Library function isEqlArr here. Standard Library isEqlArr import { isEqlArr, shuffle } from '@opentf/std'; let a = [1, 2, 3]; let b = [2, 3, 1]; isEqlArr(a, b); // true a = ['1', 1]; b = [1, '1']; isEqlArr(a, b); // true a = [1, 1, 2, 2]; b = [1, 2, 1, 2]; isEqlArr(a, b); // true a = 'Apple'.split('') b = shuffle('Apple') isEqlArr(a, b); // true a = [{a: 1}, {b: 2}]; b = [{b: 2}, {a: 1}]; isEqlArr(a, b); // true a = [{a: {b: {c: ['a', 'b', 'c']}}}, [1, 2, 3]]; b = [[1, 2, 3], {a: {b: {c: ['a', 'b', 'c']}}}]; isEqlArr(a, b); // true a = [{m: new Map([['x', 'y']])}] b = [{m: new Map([['y', 'x']])}] isEqlArr(a, b); // false import { isEqlArr, shuffle } from '@opentf/std'; let a = [1, 2, 3]; let b = [2, 3, 1]; isEqlArr(a, b); // true a = ['1', 1]; b = [1, '1']; isEqlArr(a, b); // true a = [1, 1, 2, 2]; b = [1, 2, 1, 2]; isEqlArr(a, b); // true a = 'Apple'.split('') b = shuffle('Apple') isEqlArr(a, b); // true a = [{a: 1}, {b: 2}]; b = [{b: 2}, {a: 1}]; isEqlArr(a, b); // true a = [{a: {b: {c: ['a', 'b', 'c']}}}, [1, 2, 3]]; b = [[1, 2, 3], {a: {b: {c: ['a', 'b', 'c']}}}]; isEqlArr(a, b); // true a = [{m: new Map([['x', 'y']])}] b = [{m: new Map([['y', 'x']])}] isEqlArr(a, b); // false Example: Real-World Use Case In this example, we are going to find out how many sets of the same products were in the invoices of a company. Note: If it doesn't make sense, just ignore this example. Note: import { isEqlArr } from '@opentf/std'; const invoices = [ { id: 'c2607dc9-bd74-446d-ac83-de201d158b87', products: [ { id: '4e5fe7a0-0fd2-44f3-bdcd-6a3b2eea4b50', name: 'Product A' }, { id: '863cb499-1943-473b-85f2-285ed9128c74', name: 'Product B' } ] }, { id: '6e523056-1601-41ba-b89e-6ae41164a843', products: [ { id: '4e5fe7a0-0fd2-44f3-bdcd-6a3b2eea4b50', name: 'Product A' }, { id: '401cc691-92f1-4e9e-bd78-995cb9663c5e', name: 'Product C' }, ] }, { id: '3d375953-4c60-433c-b8c2-c45628d8f2d6', products: [ { id: '863cb499-1943-473b-85f2-285ed9128c74', name: 'Product B' }, { id: '4e5fe7a0-0fd2-44f3-bdcd-6a3b2eea4b50', name: 'Product A' } ] } ] let count = 0 for (let i = 0; i < invoices.length; i += 1) { for (let j = 0; j < invoices.length; j += 1) { if (i !== j) { if (isEqlArr(invoices[i].products, invoices[j].products)) { count++ } } } } console.log(count); // 2 import { isEqlArr } from '@opentf/std'; const invoices = [ { id: 'c2607dc9-bd74-446d-ac83-de201d158b87', products: [ { id: '4e5fe7a0-0fd2-44f3-bdcd-6a3b2eea4b50', name: 'Product A' }, { id: '863cb499-1943-473b-85f2-285ed9128c74', name: 'Product B' } ] }, { id: '6e523056-1601-41ba-b89e-6ae41164a843', products: [ { id: '4e5fe7a0-0fd2-44f3-bdcd-6a3b2eea4b50', name: 'Product A' }, { id: '401cc691-92f1-4e9e-bd78-995cb9663c5e', name: 'Product C' }, ] }, { id: '3d375953-4c60-433c-b8c2-c45628d8f2d6', products: [ { id: '863cb499-1943-473b-85f2-285ed9128c74', name: 'Product B' }, { id: '4e5fe7a0-0fd2-44f3-bdcd-6a3b2eea4b50', name: 'Product A' } ] } ] let count = 0 for (let i = 0; i < invoices.length; i += 1) { for (let j = 0; j < invoices.length; j += 1) { if (i !== j) { if (isEqlArr(invoices[i].products, invoices[j].products)) { count++ } } } } console.log(count); // 2 Note: You can try out these examples on our online Node.js REPL Note: Node.js REPL Conclusion Here, we have seen various levels in comparing arrays of elements unordered. The new Standard library function is used to achieve the same for the following reasons: Cross-Environment Compatibility: Execute seamlessly in browsers, Node.js, Bun, Deno, etc. Cross-Environment Compatibility: Execute seamlessly in browsers, Node.js, Bun, Deno, etc. TypeScript Support TypeScript Support Works with both CJS & ESM Works with both CJS & ESM Supports some Older Browsers & Node.js >= 16 Supports some Older Browsers & Node.js >= 16 If you need to find out the performance of the lib, please check out these benchmarks . benchmarks benchmarks . Please don't forget to check out our important Articles: important Introducing Our New JavaScript Standard Library You Don’t Need JavaScript Native Methods! Introducing Our New JavaScript Standard Library Introducing Our New JavaScript Standard Library Introducing Our New JavaScript Standard Library You Don’t Need JavaScript Native Methods! You Don’t Need JavaScript Native Methods! You Don’t Need JavaScript Native Methods! Happy coding! 🚀 🙏 Thanks for reading. References: https://stackoverflow.com/questions/29672847/how-to-compare-contents-of-javascript-array-but-not-the-order-of-them https://stackoverflow.com/questions/29672847/how-to-compare-contents-of-javascript-array-but-not-the-order-of-them https://stackoverflow.com/questions/3243275/javascript-arrays-checking-two-arrays-of-objects-for-same-contents-ignoring-o https://stackoverflow.com/questions/3243275/javascript-arrays-checking-two-arrays-of-objects-for-same-contents-ignoring-o https://stackoverflow.com/questions/47072055/how-to-make-a-deep-comparison-of-unordered-arrays?noredirect=1&lq=1 https://stackoverflow.com/questions/47072055/how-to-make-a-deep-comparison-of-unordered-arrays?noredirect=1&lq=1 https://stackoverflow.com/questions/7837456/how-to-compare-arrays-in-javascript https://stackoverflow.com/questions/7837456/how-to-compare-arrays-in-javascript