Search code examples
arraysunderscore.jsjavascript-objects

Finding object matches in multiple arrays (more than 2)


I have 3 sources that I'm pulling data into and want to just have a new collection of the items that have a matching object (coords). I have tried several ways, including chaining underscore methods, but can't seem to extract more than 2 in a reliable way. If I use nested looping it can get messy really quickly if a parent loop doesn't have a match, but the child loop does, they get missed (if that makes sense).

I've also tried concat-ing them together into one large array, which will be fine if that's the easiest way, but can't figure out how to find the coord object matches.

The arrays should be any more than about 20 results each, so performance shouldn't really be an issue for me. Any help would be super appreciated... I've spent tons of time on different solutions and I'm at the point of throwing my laptop.

var arrays = [
  [{
    id: "NMm421ue-NSXOu7Af2CNmg",
    name: "name1",
    source: 'mapQuest',
    coords: {
      lat: 35.878,
      lng: -78.85
    }
  }, {
    id: "3233e-NSXOu7A3436gdfg",
    name: "another name",
    source: 'mapQuest',
    coords: {
      lat: 40.558,
      lng: -84.78
    }
  }],
  [{
    id: "1234567768",
    name: 'googleName',
    source: 'google',
    coords: {
      lat: 35.878,
      lng: -78.85
    }
  }, {
    id: "555446888",
    name: 'Another Google',
    source: 'google',
    coords: {
      lat: 44.866,
      lng: -65.84
    }
  }],
  [{
    id: "54sfs2198",
    name: 'Personal 1',
    source: 'personal',
    coords: {
      lat: 44.866,
      lng: -65.84
    }
  }, {
    id: "98456245f",
    name: '2nd personal',
    source: 'personal',
    coords: {
      lat: 35.878,
      lng: -78.85
    }
  }]
];


var result = arrays.shift().filter(function(v) {
  console.log('v:', v);
  return arrays.every(function(a) {
    return a.indexOf(v) !== -1;
  });
});

Expected result would be

[
  {id: "98456245f", name:'2nd personal', source: 'personal', coords: {lat: 35.878, lng: -78.85}},
  {id: "1234567768", name:'googleName', source: 'google', coords: {lat: 35.878, lng: -78.85}},
  {id: "NMm421ue-NSXOu7Af2CNmg", name: "name1", source:'mapQuest', coords: {lat: 35.878, lng: -78.85}}
]

Solution

  • If you don't care where the duplicates come from across all of the arrays, you can flatten the collection and group on lat/lng pairs. Then, filter out any of the groupings that aren't large enough to pass a size cutoff parameter threshold.

    Note that the result is returned as an array of arrays, which makes the most sense to me since there could be multiple groupings. The caller can flatten this if necessary.

    const findCoordDupes = (coords, threshold=2) => {
      return Object.values(coords.flat().reduce((a, e) => {
        const key = `${e.coords.lat} ${e.coords.lng}`;
        
        if (!a[key]) a[key] = [];
        
        a[key].push(e);
        return a;
      }, {})).filter(e => e.length > threshold);
    };
    
    const coords = [
      [{
        id: "NMm421ue-NSXOu7Af2CNmg",
        name: "name1",
        source: 'mapQuest',
        coords: {
          lat: 35.878,
          lng: -78.85
        }
      }, {
        id: "3233e-NSXOu7A3436gdfg",
        name: "another name",
        source: 'mapQuest',
        coords: {
          lat: 40.558,
          lng: -84.78
        }
      }],
      [{
        id: "1234567768",
        name: 'googleName',
        source: 'google',
        coords: {
          lat: 35.878,
          lng: -78.85
        }
      }, {
        id: "555446888",
        name: 'Another Google',
        source: 'google',
        coords: {
          lat: 44.866,
          lng: -65.84
        }
      }],
      [{
        id: "54sfs2198",
        name: 'Personal 1',
        source: 'personal',
        coords: {
          lat: 44.866,
          lng: -65.84
        }
      }, {
        id: "98456245f",
        name: '2nd personal',
        source: 'personal',
        coords: {
          lat: 35.878,
          lng: -78.85
        }
      }]
    ];
    
    console.log(findCoordDupes(coords));