2

How can I remove entries such as this from an array

  • _id = 0
  • _id = ""
  • _id = undefined
  • _id = null

and then sort and limit the output to only 7 items with the highest costs?

MyArray

[
{_id : "" , M : "4", S : "2", Costs: "6"},
{_id : "0", M : "1", S : "0", Costs: "1"},
{_id : "1", M : "1", S : "0", Costs: "1"},
{_id : "2", M : "1", S : "0", Costs: "1"},
{_id : "3", M : "0", S : "3", Costs: "3"},
{_id : "4",  M : "1", S : "0", Costs: "1"},
{_id : "5",  M : "1", S : "0", Costs: "5"},
{_id : "6",  M : "1", S : "0", Costs: "2"},
{_id : "7",  M : "1", S : "0", Costs: "5"},
{_id : "8",  M : "1", S : "0", Costs: "1"},
{_id : "9",  M : "1", S : "0", Costs: "10"}
]

DESIRED OUTPUT

[
{_id : "9",  M : "1", S : "0", Costs: "10"},
{_id : "7",  M : "1", S : "0", Costs: "5"},
{_id : "5",  M : "1", S : "0", Costs: "5"},
{_id : "3", M : "0", S : "3", Costs: "3"},
{_id : "6",  M : "1", S : "0", Costs: "2"},
{_id : "1", M : "1", S : "0", Costs: "1"},
{_id : "2", M : "1", S : "0", Costs: "1"}
]
nem035
  • 34,790
  • 6
  • 87
  • 99
justdiehard
  • 249
  • 1
  • 2
  • 12

3 Answers3

2

You don't need underscore to do this, you can just do it in plain javascript plus it is more efficient to do so since native methods are faster. The way to go is to filter out the falsey values, then sort by Costs, and finally slice the top 7 results:

Note the sort function using -, check out here why

Using plain JS

var top7 = myArray.filter(function(item) {
  return !!item; // filters out all falsey values
}).sort(function(a, b) {
  return parseInt(b.Costs) - parseInt(a.Costs); // sort descending by Costs
}).slice(0, 7); // extracts the top 7 results

Running example:

var myArray = [
{_id : "" , M : "4", S : "2", Costs: "6"},
{_id : "0", M : "1", S : "0", Costs: "1"},
{_id : "1", M : "1", S : "0", Costs: "1"},
{_id : "2", M : "1", S : "0", Costs: "1"},
{_id : "3", M : "0", S : "3", Costs: "3"},
{_id : "4",  M : "1", S : "0", Costs: "1"},
{_id : "5",  M : "1", S : "0", Costs: "5"},
{_id : "6",  M : "1", S : "0", Costs: "2"},
{_id : "7",  M : "1", S : "0", Costs: "5"},
{_id : "8",  M : "1", S : "0", Costs: "1"},
{_id : "9",  M : "1", S : "0", Costs: "10"}
];

var top7 = myArray.filter(function(item) {
  return !!item; // filters out all falsey values
}).sort(function(a, b) {
  return parseInt(b.Costs) - parseInt(a.Costs); // sort descending by Costs
}).slice(0, 7);

console.log(top7);

Using underscore

Note: Since underscore only has a sortBy method that always sorts ascending, we have to sort on the inverse of Costs to achieve the descending order:

// filter out all falsey values
var filtered = _.filter(myArray, function(item) {
  return !!item;
});

// sort descending by Costs
var sorted = _.sortBy(filtered, function(item) {
  return -parseInt(item.Costs); // Notice the '-' sign to achieve descending order
}); 

// slice the top 7 results 
var top7 = sorted.slice(0, 7);

Running example:

var myArray = [
{_id : "" , M : "4", S : "2", Costs: "6"},
{_id : "0", M : "1", S : "0", Costs: "1"},
{_id : "1", M : "1", S : "0", Costs: "1"},
{_id : "2", M : "1", S : "0", Costs: "1"},
{_id : "3", M : "0", S : "3", Costs: "3"},
{_id : "4",  M : "1", S : "0", Costs: "1"},
{_id : "5",  M : "1", S : "0", Costs: "5"},
{_id : "6",  M : "1", S : "0", Costs: "2"},
{_id : "7",  M : "1", S : "0", Costs: "5"},
{_id : "8",  M : "1", S : "0", Costs: "1"},
{_id : "9",  M : "1", S : "0", Costs: "10"}
];

var filtered = _.filter(myArray, function(item) {
  return !!item; // filters out all falsey values
});

var sorted = _.sortBy(filtered, function(item) {
  return -parseInt(item.Costs); // sort descending by Costs
}); 

var top7 = sorted.slice(0, 7);

console.log(top7);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
Community
  • 1
  • 1
nem035
  • 34,790
  • 6
  • 87
  • 99
  • Thx!! What if the _id happens to be char? – justdiehard Mar 09 '16 at 20:02
  • You're welcome. There's no such thing as a char in js, all text is a string so this will still work with strings of length 1. Additionally, `_id` field isn't used in this code so doing anything with it (including removing it) won't make a difference. – nem035 Mar 09 '16 at 20:06
  • Damn looks like it works like a charm! However I think I have written undefined as _id value at some point in my javascript chain. Could you help me a bit more to filter array element with _id = "undefined"? – justdiehard Mar 09 '16 at 20:13
  • Well, you can just add an extra condition to the `filter `method: `return !!item && item._id !== undefined;`. This will filter out all falsey values from the array and all elements whose `_id` is `undefined` – nem035 Mar 09 '16 at 20:20
  • thanks!! I got what I was looking for! Highly appreciated!! Very big thing to me! @nem – justdiehard Mar 09 '16 at 20:36
2

You could filter and then sort and then slice chaining them as below.

var result = arr.filter(function(doc){
    return !!parseInt(doc._id);
}).sort(function(a,b){
    return (parseInt(b.Costs) - parseInt(a.Costs));
}).slice(0,7);
BatScream
  • 19,260
  • 4
  • 52
  • 68
  • sort won't work because `[].sort` sorts elements alphabetically by default. The correct way is to use a `-` instead of `<` – nem035 Mar 09 '16 at 20:12
1

Another answer using underscore which uses reject to remove items with an invalid id, sortBy to sort the items and first to limit the number in the result set:

var invalidId = function(item){
    return item._id == "0" || item._id == "" || item._id == undefined || item._id == null;
}

var negateCosts = function(item){
    return -parseInt(item.Costs, 10)
}

var result = _.chain(data)
    .reject(invalidId)
    .sortBy(negateCosts)
    .first(7)
    .value()
Gruff Bunny
  • 27,738
  • 10
  • 72
  • 59
  • One quick suggestion is that there's no need for all the `||` since his invalid ids are just all falsey values in JS so simple `!item` should work. Also I think `"0"` is a valid id, although he didn't specify if he meant `0` or `"0"`. Good alternative solution regardless. – nem035 Mar 10 '16 at 01:52