19

I have two JavaScript arrays (A and B) that contain objects that I created. I want to check that all the objects in array A are contained in array B, but not necessarily in the same order.

What is the best way to do this?

Edit:

They are all actual objects, not primitives, so I will need to compare their contents and structure as well (maybe using something like JSON.stringify).

I want to do this because I'm learning Test-Driven Development, and I want to test functions that return lists of objects. I need to test whether the returned lists have the expected objects in them or not (order doesn't matter in this case).

7
  • 2
    Are they primitives such as true, false, 23 or actual objects? Also can you explain why you want to do this? There may be a better way. Commented Jul 14, 2010 at 3:54
  • Edited question for clarification.
    – Chetan
    Commented Jul 14, 2010 at 4:04
  • Why not first sort and then use JSON.stringify to compare
    – Xinus
    Commented Jul 14, 2010 at 4:07
  • Actually you can compare objects by reference. Commented Jul 14, 2010 at 4:08
  • How complex are these objects you're comparing? Do they have characteristics you're going to need to check as well (methods, etc)?
    – g.d.d.c
    Commented Jul 14, 2010 at 4:30

6 Answers 6

5

With ES6 you could use every and some (and length).

let A = [1, 2, 3];
let B = [2, 3, 1];

// all objects in A are contained in B (A ⊆ B)
// you can compare a <-> b however you'd like (here just `a === b`)
let AsubB = A.every(a => B.some(b => a === b));

// A and B are the same length
let sameLength = A.length === B.length;

// their contents are as equal as previously tested:
let equal = AsubB && sameLength;
2
  • 4
    Checking for containment, even when you use both directions, does not account for multiple equal elements; e.g., consider [1,2,3,3] and [1,2,2,3].
    – Wang Tang
    Commented Jul 26, 2020 at 15:19
  • for checking two object properties it's fine; moreover in the question is not requested to check for repeats. I used it with an object containing dates from and to and works nice.
    – Don Diego
    Commented Feb 19, 2021 at 17:48
3

Usage: isEqArrays(arr1, arr2)

//
// Array comparsion
//

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

function isEqArrays(arr1, arr2) {
  if ( arr1.length !== arr2.length ) {
    return false;
  }
  for ( var i = arr1.length; i--; ) {
    if ( !inArray( arr2, arr1[i] ) ) {
      return false;
    }
  }
  return true;
}
3
  • Is this faster than @ChaosPandion's solution?
    – Chetan
    Commented Jul 15, 2010 at 1:00
  • it's cross browser. Chaos's isn't. He uses language features which are not well-supported yet.
    – gblazex
    Commented Jul 15, 2010 at 10:46
  • 7
    This code doesn't work: isEqArrays([0, 0, 1], [0, 1, 1]) returns true.
    – callum
    Commented Aug 31, 2017 at 23:28
2

This is probably the simplest method if not the slowest.

var o = { PropA: 1, PropB: 2 };
var a = [1, 2, 3, 4, o];
var b = [2, 3, 4, 1];

var c = a.filter(function(value, index, obj) {
    return b.indexOf(value) > -1;
});

if (c.length !== a.length) {
    throw new Error("Array b is missing some elements!");
}

indexOf will only check that they refer to the same object. If you want to check value equivalence you will have to do a deep compare of the properties or use JSON.stringify as you mention in your question.

2
  • 1
    Does .indexOf check for object equivalency too? As in, if I make an o2 = { PropA: 2, PropB: 2} and put it in b, would it return something other than -1?
    – Chetan
    Commented Jul 14, 2010 at 4:19
  • 1
    As with the other answer, this returns a false positive for [0, 1, 1] and [0, 0, 1].
    – callum
    Commented Aug 31, 2017 at 23:32
0

Simple & Elegant

function isEqual(arr1, arr2) {
    if (arr1.length !== arr2.length)
        return false;
    return arr1.every(x => arr2.includes(x));
}

If duplication is important, use this

function isEqual(arr1, arr2) {
    if (arr1.length !== arr2.length)
        return false;
    arr1.sort();
    arr2.sort();
    for (var i = 0; i < arr1.length; i++) {
        if (arr1[i] !== arr2[i])
            return false;
    }
    return true;
}
1
  • 3
    isEqual([0, 1, 1], [0, 0, 1]) returns true...
    – Sarout
    Commented Jan 25, 2022 at 22:55
0

Hi it seem more difficult than I thought and I need to code it myself. Please check my solution:

//usage
const arr1 = [{
    a: 1,
    b: 2
  },
  {
    a: 2,
    b: 1
  },
  {
    a: 1,
    b: 2,
    c: 3
  },
];
const arr2 = [{
    a: 1,
    b: 2,
    c: 3
  },
  {
    a: 1,
    b: 2
  },
  {
    a: 2,
    b: 1
  },
];
alert(compareTwoArray(arr1, arr2));

function compareTwoArray(arr1, arr2) {
  if (arr1.length != arr2.length || arr1.length == arr2.length == 0) {
    return false;
  }
  //clone arr to process
  let arr01 = JSON.parse(JSON.stringify(arr1));
  let arr02 = JSON.parse(JSON.stringify(arr2));
  for (let i = (arr01.length - 1); i >= 0; i--) {
    for (let j = (arr02.length - 1); j >= 0; j--) {
      if (JSON.stringify(arr01[i]) === JSON.stringify(arr02[j])) {
        arr01.splice(i, 1);
        arr02.splice(j, 1);
      }
    }
  }
  if (arr01.length == 0 && arr02.length == 0) {
    return true;
  } else {
    return false;
  }
}

This is for array of values only:

//usage
alert(compareTwoArray([0, 0, 1, 1], [1, 0, 1, 0]));

function compareTwoArray(arr1, arr2) {
  if (arr1.length != arr2.length || arr1.length == arr2.length == 0) {
    return false;
  }
  //clone arr to process
  let arr01 = JSON.parse(JSON.stringify(arr1));
  let arr02 = JSON.parse(JSON.stringify(arr2));
  for (let i = (arr01.length - 1); i >= 0; i--) {
    for (let j = (arr01.length - 1); j >= 0; j--) {
      if (arr01[i] == arr02[j]) {
        //remove duplicate item from both array
        arr01.splice(i, 1);
        arr02.splice(j, 1);
      }
    }
  }
  if (arr01.length == 0 && arr02.length == 0) {
    return true;
  } else {
    return false;
  }
}

5
  • is it working with actual objects, not primitives?
    – MarcC
    Commented Feb 20, 2024 at 18:57
  • @MarcC I think you need to add code to compare two object instead of if (arr01[i] == arr02[j]) and then it can be work on arrays of objects Commented Feb 21, 2024 at 4:50
  • The question mentioned object comparison so your solution does not answer the question. You have to consider nested objects as well (ie. a tree of objects).
    – MarcC
    Commented Feb 21, 2024 at 7:01
  • @MarcC oh right! I just updated my answer for arrays of objects Commented Feb 21, 2024 at 8:13
  • Good, your approach is generating a lot of new objects and strings but is doing the job. I would have opted for a recursive in-place comparison.
    – MarcC
    Commented Feb 21, 2024 at 8:45
0

developing/writing code block is fine and this needs deep comparision. but as a developer, we don't need to write code from scratch. we have plenty of options. We are also having a huge npm packages to get the job done specifically developed for these use case. I have used similar-js" it did the job that you need. It extends so many use cases as well.

https://www.npmjs.com/package/similar-js

npm i similar-js

import {isSimilar} from 'similar-js'; 
const a = [
    {
      id: 0,
      name: "Ashley Lyons",
    },
    {
      id: 1,
      name: "Ophelia Erickson",
    },
    {
      id: 2,
      name: "Britney Cook",
    },
  ]

  const b = [
    
    {
      id: 2,
      name: "Britney Cook",
    },
    {
        id: 0,
        name: "Ashley Lyons",
      },
      {
        id: 1,
        name: "Ophelia Erickson",
      },
  ]

  console.log(isSimilar(a, b))

(Disclosure: I am the owner of the linked repo)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.