You didn't seem to care about perf, not sure any of the other answer did either.
Here's some benchmarks for both sameArrayMembers (ie, [1,2,2] != [1,1,2]) as well as sameArrayMembersAsSet (ie, [1,2,2] == [1,1,2])
Didn't check for [1,1,2] same as [1,2] which I probably should given if you're claiming to check for sets than you shouldn't have the length check.
const tests = { 'Maciej Krawczyk': (_arr1, _arr2) => { if (!Array.isArray(_arr1) || ! Array.isArray(_arr2) || _arr1.length !== _arr2.length) return false; var arr1 = _arr1.concat().sort(); var arr2 = _arr2.concat().sort(); for (var i = 0; i < arr1.length; i++) { if (arr1[i] !== arr2[i]) return false; } return true; }, 'canbax': (a1, a2) => { const superSet = {}; for (const i of a1) { const e = i + typeof i; superSet[e] = 1; } for (const i of a2) { const e = i + typeof i; if (!superSet[e]) { return false; } superSet[e] = 2; } for (let e in superSet) { if (superSet[e] === 1) { return false; } } return true; }, 'kennebec': (array1, array2) => { return array1.slice().sort().join(',')=== array2.slice().sort().join(','); }, 'Max Heiber': function() { const containsAll = (arr1, arr2) => arr2.every(arr2Item => arr1.includes(arr2Item)); return (arr1, arr2) => containsAll(arr1, arr2) && containsAll(arr2, arr1); }(), 'gman': (a, b) => { if (a.length !== b.length) { return false; } const counts = new Map(); for (const v of a) { const count = counts.get(v) || 0; counts.set(v, count + 1); } for (const v of b) { const count = counts.get(v); if (!count) { // undefined or 0, both mean arrays are not the same return false; } counts.set(v, count - 1); } return true; }, 'Bemmu': (a, b) => { if (Array.isArray(a) && Array.isArray(b) && a.length == b.length) { a = a.concat().sort() b = b.concat().sort() return a.reduce((acc,e,i) => acc && e === b[i], true) } else { return false; } }, 'Sandeep': (array1, array2) => { return JSON.stringify(array1.sort()) === JSON.stringify(array2.sort()); }, 'camslice': (arr1, arr2) => { const arr1test = arr1.slice().sort(); const arr2test = arr2.slice().sort(); return !arr1test.some((val, idx) => val !== arr2test[idx]); }, 'Dimitrios Stefos': (arr1, arr2) => { if (!Array.isArray(arr1) || !Array.isArray(arr2) || arr1.length!=arr2.length) return false; return arr1.length==arr1.filter(word => arr2.includes(word)).length; }, 'SC1000': (arr1, arr2, opts) => { function vKey(i, v) { return (opts?.enforceOrder ? `${i}-` : '') + `${typeof v}-${v}` } if (arr1.length !== arr2.length) return false; const d1 = {}; const d2 = {}; for (let i = arr1.length - 1; i >= 0; i--) { d1[vKey(i, arr1[i])] = true; d2[vKey(i, arr2[i])] = true; } for (let i = arr1.length - 1; i >= 0; i--) { const v = vKey(i, arr1[i]); if (d1[v] !== d2[v]) return false; } for (let i = arr2.length - 1; i >= 0; i--) { const v = vKey(i, arr2[i]); if (d1[v] !== d2[v]) return false; } return true }, 'Magnus Fohlström': (arr1, arr2) => { let count = (arr, val) => arr.reduce((count, curr) => (curr === val ? 1:0) + count, 0); return arr1.length === arr2.length && arr1.reduce((checks, val) => checks.concat(count(arr1, val) === count(arr2, val)), []).every(check => check); }, }; // ---------------------------- function createExposedPromise() { const p = {}; p.promise = new Promise((resolve, reject) => { p.resolve = resolve; p.reject = reject; }); return p; } function assert(cond) { if (!cond) { log('assert'); throw new Error(); } } async function main() { await testResults(true, 'sameArrayMembers'); await testResults(false, 'sameArrayMemembersAsSet'); async function testResults(asSet, msg) { log(`\n=======[ ${msg} ] ============`); const suite = new Benchmark.Suite(); let test; // reject if they fail simple test const a = [1,1,2]; const b = [1,2,2]; for (const [name, fn] of Object.entries(tests)) { if (fn(a, b) === asSet) { log(`${name} fails for ${msg}([${a}], [${b}])`); } else { suite.add(name, () => test(fn)); } } let endPromise; suite.on('cycle', event => log(String(event.target))); suite.on('complete', function() { log('Fastest is ' + this.filter('fastest').map('name')); endPromise.resolve(); }); async function runWith(num, title) { log(`------[ ${title} ] -----------`); const a = []; for (let i = 0; i < num; ++i) { a[i] = Math.random(); } const b = [...a]; const c = [...a]; c[c.length / 2 | 0]++; endPromise = createExposedPromise(); test = (fn) => { assert(fn(a, b)) assert(!fn(a, c)); }; suite.reset(); suite.run({'async': true}); await endPromise.promise; } await runWith(10, 'small (10)'); await runWith(100, 'medium (100)'); await runWith(10000, 'large (10000)'); } } main(); function log(...args) { const elem = document.createElement('pre'); elem.textContent = args.join(' '); document.body.appendChild(elem); }
pre { margin: 0; }
<script src="https://unpkg.com/[email protected]/lodash.js"></script> <script src="https://unpkg.com/[email protected]/benchmark.js"></script>
The results will probably change over time since JS engines get updated. Here's some results from 2020/09/28
Chrome 87
=======[ sameArrayMembers ] ============ canbax fails for sameArrayMembers([1,1,2], [1,2,2]) Max Heiber fails for sameArrayMembers([1,1,2], [1,2,2]) Dimitrios Stefos fails for sameArrayMembers([1,1,2], [1,2,2]) SC1000 fails for sameArrayMembers([1,1,2], [1,2,2]) ------[ small (10) ] ----------- Maciej Krawczyk x 246,129 ops/sec ±0.84% (66 runs sampled) kennebec x 182,234 ops/sec ±0.56% (64 runs sampled) gman x 377,356 ops/sec ±1.55% (64 runs sampled) Bemmu x 244,850 ops/sec ±0.76% (64 runs sampled) Sandeep x 100,529 ops/sec ±1.53% (63 runs sampled) camslice x 542,577 ops/sec ±0.68% (64 runs sampled) Fastest is camslice ------[ medium (100) ] ----------- Maciej Krawczyk x 12,121 ops/sec ±1.40% (63 runs sampled) kennebec x 10,219 ops/sec ±1.60% (63 runs sampled) gman x 41,225 ops/sec ±1.63% (62 runs sampled) Bemmu x 12,400 ops/sec ±1.10% (63 runs sampled) Sandeep x 12,470 ops/sec ±0.50% (64 runs sampled) camslice x 57,126 ops/sec ±0.54% (64 runs sampled) Fastest is camslice ------[ large (10000) ] ----------- Maciej Krawczyk x 30.75 ops/sec ±0.86% (42 runs sampled) kennebec x 27.35 ops/sec ±1.11% (38 runs sampled) gman x 376 ops/sec ±0.46% (62 runs sampled) Bemmu x 30.91 ops/sec ±0.77% (42 runs sampled) Sandeep x 80.33 ops/sec ±0.54% (53 runs sampled) camslice x 166 ops/sec ±0.44% (61 runs sampled) Fastest is gman =======[ sameArrayMemembersAsSet ] ============ Maciej Krawczyk fails for sameArrayMemembersAsSet([1,1,2], [1,2,2]) kennebec fails for sameArrayMemembersAsSet([1,1,2], [1,2,2]) gman fails for sameArrayMemembersAsSet([1,1,2], [1,2,2]) Bemmu fails for sameArrayMemembersAsSet([1,1,2], [1,2,2]) Sandeep fails for sameArrayMemembersAsSet([1,1,2], [1,2,2]) camslice fails for sameArrayMemembersAsSet([1,1,2], [1,2,2]) ------[ small (10) ] ----------- canbax x 110,826 ops/sec ±2.07% (63 runs sampled) Max Heiber x 2,699,807 ops/sec ±1.31% (63 runs sampled) Dimitrios Stefos x 2,910,096 ops/sec ±0.65% (62 runs sampled) SC1000 x 59,989 ops/sec ±2.61% (63 runs sampled) Fastest is Dimitrios Stefos ------[ medium (100) ] ----------- canbax x 9,624 ops/sec ±2.20% (53 runs sampled) Max Heiber x 88,945 ops/sec ±0.71% (64 runs sampled) Dimitrios Stefos x 94,425 ops/sec ±0.51% (65 runs sampled) SC1000 x 5,742 ops/sec ±0.74% (33 runs sampled) Fastest is Dimitrios Stefos ------[ large (10000) ] ----------- canbax x 59.85 ops/sec ±1.69% (46 runs sampled) Max Heiber x 13.50 ops/sec ±0.87% (26 runs sampled) Dimitrios Stefos x 15.40 ops/sec ±0.89% (30 runs sampled) SC1000 x 37.42 ops/sec ±1.47% (40 runs sampled) Fastest is canbax
Firefox 80
=======[ sameArrayMembers ] ============ canbax fails for sameArrayMembers([1,1,2], [1,2,2]) Max Heiber fails for sameArrayMembers([1,1,2], [1,2,2]) Dimitrios Stefos fails for sameArrayMembers([1,1,2], [1,2,2]) SC1000 fails for sameArrayMembers([1,1,2], [1,2,2]) ------[ small (10) ] ----------- Maciej Krawczyk x 118,391 ops/sec ±0.52% (65 runs sampled) kennebec x 70,254 ops/sec ±0.40% (67 runs sampled) gman x 201,659 ops/sec ±3.23% (57 runs sampled) Bemmu x 118,133 ops/sec ±0.67% (64 runs sampled) Sandeep x 69,484 ops/sec ±1.40% (65 runs sampled) camslice x 130,443 ops/sec ±0.55% (65 runs sampled) Fastest is gman ------[ medium (100) ] ----------- Maciej Krawczyk x 11,418 ops/sec ±2.81% (61 runs sampled) kennebec x 7,278 ops/sec ±1.37% (41 runs sampled) gman x 19,748 ops/sec ±6.60% (53 runs sampled) Bemmu x 11,535 ops/sec ±1.09% (62 runs sampled) Sandeep x 8,234 ops/sec ±1.46% (45 runs sampled) camslice x 14,277 ops/sec ±3.08% (60 runs sampled) Fastest is gman ------[ large (10000) ] ----------- Maciej Krawczyk x 65.25 ops/sec ±2.13% (49 runs sampled) kennebec x 47.73 ops/sec ±0.82% (51 runs sampled) gman x 210 ops/sec ±3.54% (54 runs sampled) Bemmu x 66.90 ops/sec ±0.53% (50 runs sampled) Sandeep x 63.13 ops/sec ±1.59% (48 runs sampled) camslice x 115 ops/sec ±1.36% (56 runs sampled) Fastest is gman =======[ sameArrayMemembersAsSet ] ============ Maciej Krawczyk fails for sameArrayMemembersAsSet([1,1,2], [1,2,2]) kennebec fails for sameArrayMemembersAsSet([1,1,2], [1,2,2]) gman fails for sameArrayMemembersAsSet([1,1,2], [1,2,2]) Bemmu fails for sameArrayMemembersAsSet([1,1,2], [1,2,2]) Sandeep fails for sameArrayMemembersAsSet([1,1,2], [1,2,2]) camslice fails for sameArrayMemembersAsSet([1,1,2], [1,2,2]) ------[ small (10) ] ----------- canbax x 79,433 ops/sec ±1.11% (57 runs sampled) Max Heiber x 1,822,200 ops/sec ±0.92% (65 runs sampled) Dimitrios Stefos x 2,258,820 ops/sec ±0.48% (65 runs sampled) SC1000 x 35,784 ops/sec ±1.42% (63 runs sampled) Fastest is Dimitrios Stefos ------[ medium (100) ] ----------- canbax x 6,726 ops/sec ±0.60% (38 runs sampled) Max Heiber x 41,620 ops/sec ±1.08% (65 runs sampled) Dimitrios Stefos x 53,041 ops/sec ±1.61% (64 runs sampled) SC1000 x 3,450 ops/sec ±0.56% (64 runs sampled) Fastest is Dimitrios Stefos ------[ large (10000) ] ----------- canbax x 44.18 ops/sec ±5.87% (42 runs sampled) Max Heiber x 5.62 ops/sec ±4.79% (19 runs sampled) Dimitrios Stefos x 6.77 ops/sec ±1.21% (21 runs sampled) SC1000 x 24.18 ops/sec ±3.50% (36 runs sampled) Fastest is canbax
Safari 14
=======[ sameArrayMembers ] ============ canbax fails for sameArrayMembers([1,1,2], [1,2,2]) Max Heiber fails for sameArrayMembers([1,1,2], [1,2,2]) Dimitrios Stefos fails for sameArrayMembers([1,1,2], [1,2,2]) SC1000 fails for sameArrayMembers([1,1,2], [1,2,2]) ------[ small (10) ] ----------- Maciej Krawczyk x 142,798 ops/sec ±0.50% (65 runs sampled) kennebec x 118,073 ops/sec ±1.12% (63 runs sampled) gman x 760,109 ops/sec ±0.46% (66 runs sampled) Bemmu x 136,265 ops/sec ±0.48% (63 runs sampled) Sandeep x 69,868 ops/sec ±0.44% (64 runs sampled) camslice x 155,548 ops/sec ±0.45% (64 runs sampled) Fastest is gman ------[ medium (100) ] ----------- Maciej Krawczyk x 8,479 ops/sec ±0.52% (46 runs sampled) kennebec x 5,992 ops/sec ±2.54% (34 runs sampled) gman x 83,390 ops/sec ±0.37% (64 runs sampled) Bemmu x 8,615 ops/sec ±0.56% (63 runs sampled) Sandeep x 5,943 ops/sec ±0.67% (64 runs sampled) camslice x 8,753 ops/sec ±0.45% (47 runs sampled) Fastest is gman ------[ large (10000) ] ----------- Maciej Krawczyk x 62.66 ops/sec ±0.87% (51 runs sampled) kennebec x 46.46 ops/sec ±0.66% (48 runs sampled) gman x 615 ops/sec ±2.33% (60 runs sampled) Bemmu x 60.98 ops/sec ±1.28% (52 runs sampled) Sandeep x 49.11 ops/sec ±2.07% (47 runs sampled) camslice x 66.33 ops/sec ±4.44% (50 runs sampled) Fastest is gman =======[ sameArrayMemembersAsSet ] ============ Maciej Krawczyk fails for sameArrayMemembersAsSet([1,1,2], [1,2,2]) kennebec fails for sameArrayMemembersAsSet([1,1,2], [1,2,2]) gman fails for sameArrayMemembersAsSet([1,1,2], [1,2,2]) Bemmu fails for sameArrayMemembersAsSet([1,1,2], [1,2,2]) Sandeep fails for sameArrayMemembersAsSet([1,1,2], [1,2,2]) camslice fails for sameArrayMemembersAsSet([1,1,2], [1,2,2]) ------[ small (10) ] ----------- canbax x 167,041 ops/sec ±0.63% (64 runs sampled) Max Heiber x 1,281,054 ops/sec ±0.74% (59 runs sampled) Dimitrios Stefos x 1,127,639 ops/sec ±0.98% (64 runs sampled) SC1000 x 112,824 ops/sec ±0.37% (64 runs sampled) Fastest is Max Heiber ------[ medium (100) ] ----------- canbax x 8,784 ops/sec ±0.53% (47 runs sampled) Max Heiber x 37,824 ops/sec ±0.52% (65 runs sampled) Dimitrios Stefos x 41,238 ops/sec ±0.85% (63 runs sampled) SC1000 x 6,181 ops/sec ±0.61% (35 runs sampled) Fastest is Dimitrios Stefos ------[ large (10000) ] ----------- canbax x 63.83 ops/sec ±2.46% (49 runs sampled) Max Heiber x 5.41 ops/sec ±0.52% (18 runs sampled) Dimitrios Stefos x 6.02 ops/sec ±1.32% (19 runs sampled) SC1000 x 42.25 ops/sec ±1.45% (45 runs sampled) Fastest is canbax