How to compare two arrays and then return the index of the difference?
Asked Answered
P

4

9

I have two arrays that I need to check the difference upon and return the index of that difference.

For example, I currently have two arrays that get updated when the input's value is changed. The newTags array gets updated whenever there is a new tag within the input, such as @testing. I need to compare the newTags array with the oldTags array and return the index of the difference.

I am currently stringifying both arrays and comparing them that way, although it is unable to return the index of the difference.

var newTags = [];
var oldTags = [];

$input.on('keyup', function () {
    var newValue = $input.val();
    var pattern = /@[a-zA-Z]+/ig;
    var valueSearch = newValue.search(pattern);

    if (valueSearch >= 0) {
        newTags = newValue.match(pattern);

        if ((newTags + "") != (oldTags + "")) {
            //Need index of difference here
            console.log(newTags, oldTags);
        }

        oldTags = newTags;
    }
});

Working example

Pinzler answered 18/3, 2015 at 2:54 Comment(6)
Search for a value in an array only? or Search for a value and it be at the same index as the other array?Runnerup
@Runnerup - For example, newTags could be ["@testing", "@hello"] and oldTags could be ["@test", "@hello"]. Therefore the index of the difference is 0 since the first value in the array is different.Pinzler
That confused me more.Runnerup
@Runnerup - Hahaha, thats probably my bad. All I want to do is compare newTags with oldTags and return the position in the array of the difference.Pinzler
Now that I think about it, a simple $.each loop may be the best solution...Pinzler
I used 2 loops in my solution.Runnerup
P
2

You can use a filter to find both the different values and indexes at the same time.

JSFiddle: https://jsfiddle.net/k0uxtnkd/

Array.prototype.diff = function(a) {
    var source = this;
    return this.filter(function(i) {
        if (a.indexOf(i) < 0) {
            diffIndexes.push(source.indexOf(i));
            return true;
        } else {
            return false;
        }
    });
};
var diffIndexes = [];
var newTags = ['a','b','c'];
var oldTags = ['c'];
var diffValues = newTags.diff(oldTags);
console.log(diffIndexes); // [0, 1]
console.log(diffValues); // ['a', 'b']

To convert this to a function instead of add it to the array prototype: JSFiddle: https://jsfiddle.net/k0uxtnkd/1/

function arrayDiff(a, b) {
    return a.filter(function(i) {
        if (b.indexOf(i) < 0) {
            diffIndexes.push(a.indexOf(i));
            return true;
        } else {
            return false;
        }
    });
};
var diffIndexes = [];
var newTags = ['a','b','c'];
var oldTags = ['c'];
var diffValues = arrayDiff(newTags, oldTags);
console.log(diffIndexes); // [0, 1]
console.log(diffValues); // ['a', 'b']
Paradise answered 18/3, 2015 at 3:10 Comment(1)
Nice one. How could I convert that utility function to a normal function?Pinzler
C
3

You don't need to loop through both arrays, you can simply loop through both simultaneously:

var findDivergence = function (a1, a2) {
    var result = [], longerLength = a1.length >= a2.length ? a1.length : a2.length;
    for (i = 0; i < longerLength; i++){
        if (a1[i] !== a2[i]) {
            result.push(i);
        }
    }
    return result;
};

console.log(findDivergence(["a","b","c","d","e","f","g","h","i"], ["a","b","d","r","e","q","g"]));
//outputs [2, 3, 5, 7, 8]

This is significantly more efficient than double-looping or using indexOf (both of which will search the second array many more times than necessary). This also handles cases where the same item shows up more than once in a given array, though if one array is longer than the other and the longer one contains an element that is undefined, that index will count as a match.

Creepy answered 18/3, 2015 at 6:15 Comment(0)
P
2

You can use a filter to find both the different values and indexes at the same time.

JSFiddle: https://jsfiddle.net/k0uxtnkd/

Array.prototype.diff = function(a) {
    var source = this;
    return this.filter(function(i) {
        if (a.indexOf(i) < 0) {
            diffIndexes.push(source.indexOf(i));
            return true;
        } else {
            return false;
        }
    });
};
var diffIndexes = [];
var newTags = ['a','b','c'];
var oldTags = ['c'];
var diffValues = newTags.diff(oldTags);
console.log(diffIndexes); // [0, 1]
console.log(diffValues); // ['a', 'b']

To convert this to a function instead of add it to the array prototype: JSFiddle: https://jsfiddle.net/k0uxtnkd/1/

function arrayDiff(a, b) {
    return a.filter(function(i) {
        if (b.indexOf(i) < 0) {
            diffIndexes.push(a.indexOf(i));
            return true;
        } else {
            return false;
        }
    });
};
var diffIndexes = [];
var newTags = ['a','b','c'];
var oldTags = ['c'];
var diffValues = arrayDiff(newTags, oldTags);
console.log(diffIndexes); // [0, 1]
console.log(diffValues); // ['a', 'b']
Paradise answered 18/3, 2015 at 3:10 Comment(1)
Nice one. How could I convert that utility function to a normal function?Pinzler
R
1
for(var i=0; i < newTags.length; i++) {
    for(var j=0; j < oldTags.length; j++) {
        if(newTags[i] === oldTags[j]) {
            console.log("match found");
            console.log("Match found for value: " + newTags[i] + " at index in oldTags: " + j + );
         }
         else{
           console.log("match not found");
         }
    }
}

Using 2 loops you can do a quick check, in the if statements add what you want to happen.

Runnerup answered 18/3, 2015 at 3:7 Comment(0)
F
0

Below is a performance comparison of three common methods to perform the task asked in this question.

const arr1 = ['A', 'B', 'C'];
const arr2 = ['A', 'D', 'C', 'E'];

// Filter indexOf
function diffArray1(a1, a2) {
  let aDiffs = [];
  a1.filter((i) => {
    if (a2.indexOf(i) < 0) {
      aDiffs.push(a1.indexOf(i));
    }
  });
  return aDiffs;
};

// Loop indexOf
function diffArray2(a1, a2) {
  let aDiffs = [];
  for (let i=0; i<a1.length; ++i) {
    if (a2.indexOf(a1[i]) < 0) {
      aDiffs.push(a1.indexOf(a1[i]));
    }
  }
  return aDiffs;
};

// Loop equality
function diffArray3(a1, a2) {
  let aDiffs = [];
  for (let i=0; i<a1.length; ++i) {
    if (a1[i] !== a2[i]) {
      aDiffs.push(i);
    }
  }
  return aDiffs;
};

diffArray1(arr2, arr1); // Returns [1, 3]
diffArray2(arr2, arr1); // Returns [1, 3]
diffArray3(arr2, arr1); // Returns [1, 3]

diffArray3() is the fastest in Chrome v102.0.5005.63 (64-bit) on my system (Intel Core i7-7700HQ 32GB RAM). diffArray1() is about 38% slower and diffArray2() is about 22.5% slower. Here's the test suite:

https://jsbench.me/59l42hhpfs/1

Feel free to fork this and add more methods; please leave the URL of the fork in the comment if you do this.

Forkey answered 6/6, 2022 at 8:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.