Filter array based on an object's property value relative to how many times it occurs in other elements

StackOverflow https://stackoverflow.com/questions/22127562

문제

So say I have this array:

[
     {
        source:"A",
        country:"United States",
        region:"Illinois",
        city:"Chicago"
     },
     {
        source:"B",
        country:"United States",
        region:"Illinois",
        city:"Rock Falls"
     },
     {
        source:"C",
        country:"United States",
        region:"Illinois",
        city:"Sterling"
     },
     {
        source:"D",
        country:"United States",
        region:"Illinois",
        city:"Rock Falls"
     },
     {
        source:"E",
        country:"United States",
        region:"Illinois",
        city:"Rock Falls"
     }
  ]

I'm trying to "crowd source" some ip to location data, and I have five sources that each return an object with country, region, city properties, and of course source being that particular source.

What would be the best way to choose the ideal result using underscore.js under these conditions:

  1. If there is a (city, region) pair that occurs more times than any other pair, select that pair (and the country attribute).

  2. If there is no pair that occurs more than another pair, example: (a,a,b,b,c), (a,b,c,d,e) then choose source E and its information.

  3. If source E is not present and there are no pairs in common, choose a random source.

  4. If there is only one source, obviously choose it.

It's also possible for some sources to not be present.

도움이 되었습니까?

해결책

Underscore is my fave. This meets all your conditions. In the case of a zero-length array being passed, it returns undefined, since you didn't mention what you wanted to happen there.

var finder = function(arr){
  var fTable = _.chain(arr).groupBy(function(elem){
    return elem.region+elem.city+elem.country;
  }).sortBy("length").reverse().value();
  return (fTable[0] && fTable[1] && fTable[0].length > fTable[1].length && fTable[0][0])
      || _(arr).findWhere({source: 'E'}) || _(arr).shuffle()[0];
};

Cheers!

다른 팁

I think the countBy method will do it. Then you will want to get the maximum value (but not if it's equal to the second one), so you would need a top-K partial sort algorithm. Screw it, with 5 elements we'd just use sortBy.

var sorted = _.chain(results)
  .countBy(results, function(r) { return JSON.stringify(_.omit(r, "source")); })
  .map(function(c, r) { r = JSON.parse(r); r.occurrences = c; })
  .sortBy("occurrences").reverse()
  .value();
return sorted.length > 1
  && sorted[0].occurrences == sorted[1].occurrences
  && _.findWhere(results, {source:"E"})
  || sorted[0];
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top