James
James

Reputation: 753

Filter and sort a JavaScript array

I have an array like this:

[{
    "number": "4",
    "fileName": "fileXX",
    "rating": {
        "average": 6.4
    }
}, {
    "number": "3",
    "fileName": "fileXX",
    "rating": {
        "average": 5.4
    }
}, {
    "number": "4",
    "fileName": "fileXX",
    "rating": {
        "average": 5.4
    }
}]

I am trying to create a new array with the following criteria:

  1. Get highest rating (array.rating.average) of each number (array.number)

Output should be:

[{
    "number": "4",
    "fileName": "fileXX",
    "rating": {
        "average": 6.4
    }
}, {
    "number": "3",
    "fileName": "fileXX",
    "rating": {
        "average": 5.4
    }
}
}]

I have just managed to sort by highest rating:

array.sort(function(a , b) {
    return a.rating.average - b.rating.average;
});
array.reverse();

But, now, I just only want one object per duplicate array.number, keeping the one that has the highest array.rating.average.

Upvotes: 9

Views: 84741

Answers (4)

jenish
jenish

Reputation: 171

Simply you can use lodash method for sort by anything that you want to sort by fileName, number, etc.

const _ = require('lodash');

var data = [{
  "number": "4",
  "fileName": "fileXX",
  "rating": {
    "average": 6.4
  }
}, {
  "number": "3",
  "fileName": "fileXX",
  "rating": {
    "average": 5.4
  }
}, {
  "number": "4",
  "fileName": "fileXX",
  "rating": {
    "average": 5.4
  }
}]

var result = _.sortBy(data, ['number']);

console.log(result)

Output:
[ { number: '3', fileName: 'fileXX', rating: { average: 5.4 } },
  { number: '4', fileName: 'fileXX', rating: { average: 6.4 } },
  { number: '4', fileName: 'fileXX', rating: { average: 5.4 } } ]

Upvotes: 0

StardustGogeta
StardustGogeta

Reputation: 3406

arr = [{
    "number": "4",
    "fileName": "fileXX",
    "rating": {
        "average": 6.4
    }
}, {
    "number": "3",
    "fileName": "fileXX",
    "rating": {
        "average": 5.4
    }
}, {
    "number": "4",
    "fileName": "fileXX",
    "rating": {
        "average": 5.4
    }
}]

arr = arr.sort(function(a,b){return b.number-a.number || b.rating.average-a.rating.average}).filter(function(a,b,c){return !b || c[b-1].number != a.number});
console.log(arr);

I believe that this will solve your problem by sorting and filtering.

EDIT: Should now support older browsers.

Upvotes: 0

Haibara Ai
Haibara Ai

Reputation: 10897

array.sort((a, b) => {
  if(a.number === b.number) {
    // If two elements have same number, then the one who has larger rating.average wins
    return b.rating.average - a.rating.average;
  } else {
    // If two elements have different number, then the one who has larger number wins
    return b.number - a.number;
  }
});


array = array.filter((element, index) => {
  return index === 0 || element.number !== array[index-1].number;
});

For your test case,

[{
  "number": "4",
  "fileName": "fileXX",
  "rating": {
    "average": 6.4
  }
}, {
  "number": "3",
  "fileName": "fileXX",
  "rating": {
    "average": 5.4
  }
}, {
  "number": "4",
  "fileName": "fileXX",
  "rating": {
    "average": 5.4
  }
}]

After sorting, the output would be

[{
  "number": "4",
  "fileName": "fileXX",
  "rating": {
    "average": 6.4
  }
}, {
  "number": "4",
  "fileName": "fileXX",
  "rating": {
    "average": 5.4
  }
}, {
  "number": "3",
  "fileName": "fileXX",
  "rating": {
    "average": 5.4
  }
}]

And after filter, the final result:

[{
  "number": "4",
  "fileName": "fileXX",
  "rating": {
    "average": 6.4
  }
}, {
  "number": "3",
  "fileName": "fileXX",
  "rating": {
    "average": 5.4
  }
}]

Upvotes: 13

Daniel Tran
Daniel Tran

Reputation: 6169

First you create a dictionary for keeping the highest rating for each number:

var data = [{
    "number": "4",
    "fileName": "fileXX",
    "rating": {
        "average": 6.4
    }
}, {
    "number": "3",
    "fileName": "fileXX",
    "rating": {
        "average": 5.4
    }
}, {
    "number": "4",
    "fileName": "fileXX",
    "rating": {
        "average": 5.4
    }
}];


var filterMap = {};
data.forEach(function (item) {
  if (!filterMap[item.number] || filterMap[item.number].rating.average < item.rating.average) {
    filterMap[item.number] = item;
  }
})

var result = [];

for (var number in filterMap) {
  result.push(filterMap[number]);
}


result.sort(function(a , b) {
   return b.rating.average - a.rating.average;
});

console.log(result);

Upvotes: 1

Related Questions