简体   繁体   中英

Finding intersection of arrays not working?

I have a two dimensional array with an arbitrary number of elements in each dimension, so it's an [m][n] array, but the second dimension length ( n ) is variable.

Each element in the second dimension contains a number and there will only be one number that exists in all of the dimensions.

So, for example, the array might be:

[
    [
        126, 
        131, 
        138, 
        139, 
        140, 
        143
    ],
    [
        126,
        201
    ]
]

Keep in mind that m can be > 2.

Here's my code:

var theArray = [
  [126, 131, 138, 139, 140, 143],
  [126, 201]
];

for(var i = 0; i < theArray.length; i++) // loop through each array of numbers
{
    $.each(theArray[i], function(index, value) // loop through all of the numbers in this array
    {
        var nextArray = (i+1<theArray.length?theArray[i+1]:theArray[0]);
        if($.inArray(value, nextArray) == -1) // if this number is not in the next array
        {
            console.log("removing index: " + index + ", value: " + value);
            theArray[i].splice(index, 1); // remove the number from the array
        }
    });
}
console.log(theArray);

The output is this:

removing index: 1, value: 131
removing index: 2, value: 139
removing index: 3, value: 143
removing index: 4, value: undefined
removing index: 5, value: undefined
removing index: 1, value: 201

Array
    [
        [
            126, 
            138, 
            140, 
        ],
        [
            126
        ]
    ]

JSFIDDLE: http://jsfiddle.net/hDL8K/

As you can see, it almost works, but it fails to remove two of the values.

I think this might have something to do with the index in the foreach loop increasing with each loop and the array size decreasing because elements are being removed, but I'm not sure.

Why is this not working, and how can I fix it?

Functional version with jQuery

var theArrays = [[126, 131, 138, 139, 140,143],[126, 201]],result = theArrays[0];

$.each(theArrays, function(index, currentArray) {
    result = $.grep(result, function(currentElement) {
        return currentArray.indexOf(currentElement) !== -1;
    });
});

console.log(result);

Simple JavaScript version:

var theArrays = [[126, 131, 138, 139, 140,143],[126, 201]],result = theArrays[0];

for (var i = 1; i < theArrays.length; i += 1) {
    for (var j = 0; j < result.length; j += 1) {
        if (theArrays[i].indexOf(result[j]) === -1) {
            result.splice(j, 1);
            j -= 1;
        }
    }
}

console.log(result);

Output

[ 126 ]

If the arrays are too big, then its better to convert them to Objects and then find the intersection. Because item lookup in Objects will be much faster for larger arrays.

var theObjects = [];
for (var i = 0; i < theArrays.length; i += 1) {
    var tempObject = {};
    for (var j = 0; j < theArrays[i].length; j += 1) {
        tempObject[theArrays[i][j]] = true;
    }
    theObjects.push(tempObject);
}

var intersection = theObjects[0], result = [];
for (var i = 1; i < theArrays.length; i += 1) {
    for (var key in intersection) {
        if (theObjects[i].hasOwnProperty(key) === false) {
            delete intersection[key];
        }
    }
}

for (var key in intersection) {
    result.push(parseInt(key));
}

console.log(result);

I expect your problem stems from the fact that your array lengths are being modified as you remove items from the array. Rather than manipulating the array directly, you could have a function construct a new array with your result. I find in general this approach can help reduce bugs in code. From your existing code it could be something like this:

function intersect(theArray){
    var result = [];
    for(var i = 0; i < theArray.length; i++){
        var row = [];
        $.each(theArray[i], function(index, value){
            var nextArray = (i+1 < theArray.length
                             ?theArray[i+1]:theArray[0]);
            if($.inArray(value, nextArray) != -1) {
                row.push(theArray[i][index]);    
            }
        });
        result.push(row);        
    }
    return result;
}

Example Here . Though that does produce a multidimensional array containing intersections - you may just want the first element of it.

Don't know exactly where the problem in your solution is, but..
Here you have a solution

var theArray = [
  [126, 131, 138, 139, 140, 143],
  [126, 201]
];

//Finds intersection of 2 arrays, returns new array
function intersect_safe(a, b){
  var ai=0, bi=0;
  var result = [];    
  while( ai < a.length && bi < b.length )  {
     if      (a[ai] < b[bi] ){ ai++; }
     else if (a[ai] > b[bi] ){ bi++; }
     else{ /* they're equal */     
       result.push(a[ai]);
       ai++;
       bi++;
     }
  }
  return result;
}

for(var i = 0; i < theArray.length; i++){ // loop through each array of numbers    
    var nextIndex = (i+1) % theArray.length;
    theArray[i] = intersect_safe(theArray[i], theArray[nextIndex]);
}
console.log(theArray);

EDIT : If you want to find the intersection without modifing the original array, just change the last lines of code by:

var intersection = theArray[0] || [];
for(var i = 0; i < theArray.length; i++){ 
    intersection = intersect_safe(intersection, theArray[i]);
}
console.log(intersection);

Output: [126]

Cheers, from La Paz, Bolivia

I updated your method a little bit:

for(var i = 0; i < theArray.length; i++) // loop through each array of numbers
{
    $.each(theArray[i], function(index, value) // loop through all of the numbers in this array
    {
        var nextArray = theArray[i + 1];

        if(nextArray !== undefined && $.inArray(value, nextArray) == 0) 
        {
           console.log("removing index: " + index + ", value: " + value);
           theArray[i].splice(index, 1); // remove the number from the array
        }

    });
}

Try it now: http://jsfiddle.net/SabdielRivera/hDL8K/2/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM