0

I've searched SO for a way to do this but most questions only support two arrays (I need a solution for multiple arrays).

I don't want to compare exact objects, I want to compare objects by their ID, as their other parameters may differ.

So here's the example data:

data1 = [{'id':'13','name':'sophie'},{'id':'22','name':'andrew'}, etc.]
data2 = [{'id':'22','name':'mary'},{'id':'85','name':'bill'}, etc.]
data3 = [{'id':'20','name':'steve'},{'id':'22','name':'john'}, etc.]
...

I'd like to return all objects whose ID appears in all arrays, and I don't mind which of the set of matched objects is returned.

So, from the data above, I'd expect to return any one of the following:

{'id':'22','name':'andrew'}
{'id':'22','name':'mary'}
{'id':'22','name':'john'}

Thanks

freedomn-m
  • 27,664
  • 8
  • 35
  • 57
Sean H
  • 1,045
  • 1
  • 14
  • 32
  • `data.find(el => el.id === '22')` – Rayon May 11 '17 at 09:59
  • @Rayon what is `data`? If this is a solution can you please post it as a solution? – Sean H May 11 '17 at 10:01
  • This would be a lot easier if `data` was an array of arrays, instead of a set of distinct variables – Alnitak May 11 '17 at 10:02
  • @Alnitak I can put all the arrays into an array called `data`, that's fine. But I still don't see what the number 22 has to do with my question :) – Sean H May 11 '17 at 10:04
  • 1
    @Seano not me - that was someone else, who appears to have incorrectly assumed that you specifically want 22, and not which ever ID happens to be the one that's in every array. – Alnitak May 11 '17 at 10:09
  • Are the IDs guaranteed to be unique within each sub array ? – Alnitak May 11 '17 at 10:10
  • "*most questions only support two arrays*" - do you have an example question that nearly matches what you want - might be easier to adapt – freedomn-m May 11 '17 at 10:11
  • @Alnitak don't worry, I know the confusion originated from Rayon but I actually meant to follow up with you – Sean H May 11 '17 at 10:15
  • @Alnitak yes, the IDs are unique within each sub array – Sean H May 11 '17 at 10:16

5 Answers5

2

First, you really need an array of arrays - using a numeric suffix is not extensible:

let data = [ data1, data2, ... ];

Since you've confirmed that the IDs are unique within each sub array, you can simplify the problem by merging the arrays, and then finding out which elements occur n times, where n is the original number of sub arrays:

let flattened = data.reduce((a, b) => a.concat(b), []);

let counts = flattened.reduce(
    (map, { id }) => map.set(id, (map.get(id) || 0) + 1), new Map()
);

and then you can pick out those objects that did appear n times, in this simple version they'll all come from the first sub array:

let found = data[0].filter(({ id }) => counts.get(id) === data.length);

Picking an arbitrary (unique) match from each sub array would be somewhat difficult, although picking just one row of data and picking the items from that would be relatively easy. Either would satisfy the constraint from the question.

Alnitak
  • 334,560
  • 70
  • 407
  • 495
  • I get `Uncaught SyntaxError: Unexpected token }` on the map line – Sean H May 11 '17 at 10:43
  • this is ES6 code, that requires a modern browser. I did also just fix a typo on the `.find` line – Alnitak May 11 '17 at 10:44
  • Can you make it into a snippet? – freedomn-m May 11 '17 at 10:45
  • @Alnitak ok the code runs now but it only gives me the first match. I need it to find all matches. – Sean H May 11 '17 at 10:47
  • @Seano you wrote: "I'd expect to return any _**one**_ of the following:" – Alnitak May 11 '17 at 10:48
  • ah, but there could be multiple IDs that each appear in every array? Your test data didn't demonstrate that. – Alnitak May 11 '17 at 10:50
  • @Alnitak The full sentence in my question which you refer to is "I'd like to return all objects whose ID appears in all arrays, and I don't mind which of the set of matched objects is returned." - so you see I require all matches. – Sean H May 11 '17 at 10:51
  • @Alnitak yes, here's your fiddle with the data updated - it should show both 13 and 22: https://jsfiddle.net/qy5ex8dg/1/ – freedomn-m May 11 '17 at 10:52
  • @Alnitak not sure what you mean by this "ah, but there could be multiple IDs that each appear in every array? Your test data didn't demonstrate that." – Sean H May 11 '17 at 10:52
  • you didn't have the "13" appearing in all entries in the question – Alnitak May 11 '17 at 10:53
  • @Alnitak sorry but still not sure what you mean by the 13 comment? Could you please elaborate. – Sean H May 11 '17 at 11:01
  • what I meant was that your sample data was insufficient to demonstrate that you want _one_ of _every_ value with the multiple IDs. The only multiple ID in the question was 22. – Alnitak May 11 '17 at 11:04
  • in any event, I've updated my code to pick out all multiple ID values now, albeit it'll always pick the ones from data[0] – Alnitak May 11 '17 at 11:05
1
If you want the unique object by Name

data1 = [{'id':'13','name':'sophie'},{'id':'22','name':'mary'}]
data2 = [{'id':'26','name':'mary'},{'id':'85','name':'bill'}]
data3 = [{'id':'29','name':'sophie'},{'id':'22','name':'john'}]


flattened = [ ...data1, ...data2, ...data3 ];

counts = flattened.reduce(
    (map, { name }) => map.set(name, (map.get(name) || 0) + 1), new Map()
);

names = []

found = flattened.filter(({ name }) => {
    if ((counts.get(name) > 1) && (!names.includes(name))) {
        names.push(name);
        return true
    }
    return false
});
Vijay Chouhan
  • 4,613
  • 5
  • 29
  • 35
0

its too many loops but , if u can find the common id which is present in all the arrays then it would make your finding easier i think .you can have one array value as reference to find the common id

var global = [];
for(var i = 0;i<data1.length;i++){
var presence = true;
for(var j=0;j<arrays.length;j++){
    var temp = arrays[j].find(function(value){
        return data1[i].id == value.id;
    });
    if(!temp){
        presence = false;
        break;
    }
}
    if(presence){
       global.push(data1[i].id)
    }
}
console.log(global);

var data1 = [{'id':'13','name':'sophie'},{'id':'22','name':'andrew'}];
var data2 = [{'id':'22','name':'mary'},{'id':'85','name':'bill'}];
var data3 = [{'id':'20','name':'steve'},{'id':'22','name':'john'}];
var arrays = [data1, data2, data3];
var global = [];
for(var i = 0;i<data1.length;i++){
    var presence = true;
 for(var j=0;j<arrays.length;j++){
  var temp = arrays[j].find(function(value){
   return data1[i].id == value.id;
  });
  if(!temp){
   presence = false;
            break;
  }
 }
if(presence){
 global.push(data1[i].id)
}
}
console.log(global);
subramanian
  • 1,125
  • 1
  • 12
  • 12
0

There's mention you you need n arrays, but also, given that you can:

put all the arrays into an array called data

you can:

  • combine your arrays
  • get a list of duplicated IDs (via sort by ID)
  • make that list unique (unique list of IDs)
  • find entries in the combined list that match the unique IDs
  • where the count of those items match the original number of arrays

Sample code:

// Original data
var data1 = [{'id':'13','name':'sophie'},{'id':'22','name':'andrew'}]
var data2 = [{'id':'22','name':'mary'},{'id':'85','name':'bill'}]
var data3 = [{'id':'13','name':'steve'},{'id':'22','name':'john'}]

var arraycount = 3;

// Combine data into a single array

// This might be done by .pushing to an array of arrays and then using .length

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort?v=control
var data = [].concat(data1).concat(data2).concat(data3);
//console.log(data)

// Sort array by ID
// http://stackoverflow.com/questions/840781/easiest-way-to-find-duplicate-values-in-a-javascript-array
var sorted_arr = data.slice().sort(function(a, b) {
  return a.id - b.id;
});
//console.log(sorted_arr)

// Find duplicate IDs
var duplicate_arr = [];
for (var i = 0; i < data.length - 1; i++) {
  if (sorted_arr[i + 1].id == sorted_arr[i].id) {
    duplicate_arr.push(sorted_arr[i].id);
  }
}

// Find unique IDs
// http://stackoverflow.com/questions/1960473/unique-values-in-an-array
var unique = duplicate_arr.filter(function(value, index, self) {
  return self.indexOf(value) === index;
});
//console.log(unique);

// Get values back from data
//https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter?v=control
var matches = [];
for (var i = 0; i < unique.length; ++i) {
  var id = unique[i];
  matches.push(data.filter(function(e) {
    return e.id == id;
  }))
}
//console.log(matches)
// for data set this will be 13 and 22

// Where they match all the arrays
var result = matches.filter(function(value, index, self) {
  return value.length == arraycount;
})
//console.log("Result:")
console.log(result)

Note: There's very likely to be more efficient methods.. I've left this in the hope part of it might help someone

freedomn-m
  • 27,664
  • 8
  • 35
  • 57
-1

var arr1 = ["558", "s1", "10"]; 
var arr2 = ["55", "s1", "103"]; 
var arr3 = ["55", "s1", "104"]; 
var arr = [arr1, arr2, arr3]; 
   
console.log(arr.reduce((p, c) => p.filter(e => c.includes(e))));   
 
// output ["s1"]