How to Compare Same Contents but Different Ordered Arrays in JavaScript?
Tags: javascript, array, compare, unordered
Published: 2024-04-22 11:06:32

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, ensuring that by the end of this article.

## Basics

This is for Beginners, in JavaScript, comparing two arrays with equality operators simply do not work.

```javascript
[] == [] // false
[] === [] // false
```

## Comparing Two Arrays

Let us begin with regular array comparisons.

```javascript
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 ordered.

```javascript
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.

```javascript
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.

```javascript
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 type of values.

```javascript
arraysEqual(['1', 1], [1, '1']); // false
```

As you can see our function **failed** even with the two arrays contain same values.

Let's fix this.

```javascript
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;
}
```

```javascript
arraysEqual(['1', 1], [1, '1']); // true
```

## Level 3

Let's test the `arraysEqual` function with array of objects.

```javascript
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 different method.

```javascript
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.

```javascript
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 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.

```javascript
function inArray(array, el) {
  for (var i = array.length; i--; ) {
    if (_.isEqual(array[i], el)) return true;
  }
  return false;
}
```

Now let's try it.

```javascript
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/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.

```javascript
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](https://js-std.pages.dev/) function [isEqlArr](https://js-std.pages.dev/Assert/isEqlArr) here.

```javascript
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.

```javascript
import { isEqlArr } from '@opentf/std';

const invoices = [
  {
    userID: 'c2607dc9-bd74-446d-ac83-de201d158b87',
    products: [
      {
        id: '4e5fe7a0-0fd2-44f3-bdcd-6a3b2eea4b50',
        name: 'Product A'
      },
       {
        id: '863cb499-1943-473b-85f2-285ed9128c74',
        name: 'Product B'
      }
    ]
  },
  {
    userID: '6e523056-1601-41ba-b89e-6ae41164a843',
    products: [
      {
        id: '4e5fe7a0-0fd2-44f3-bdcd-6a3b2eea4b50',
        name: 'Product A'
      },
       {
        id: '401cc691-92f1-4e9e-bd78-995cb9663c5e',
        name: 'Product C'
      },
      
    ]
  },
  {
    userID: '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](https://node-repl.pages.dev/)

## Conclusion

Here, we have seen various levels in comparing arrays 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 &gt;= 16
    

If you need to find out the performance of the lib, please check out these [**benchmarks**.](https://js-std.pages.dev/#benchmarks)

Please don't forget to check out our `important` Articles:

* [**Introducing Our New JavaScript Standard Library**](https://dev.to/thangaganapathy/introducing-our-new-javascript-standard-library-4k22)
    
* [**You Don’t Need JavaScript Native Methods!**](https://dev.to/thangaganapathy/you-dont-need-javascript-native-methods-58bo)
    

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)