10

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.

6
  • 1
    Can you show us what you have tried? Commented Sep 3, 2016 at 3:10
  • Possible duplicate with stackoverflow.com/questions/2722159/… and stackoverflow.com/questions/1129216/… Commented Sep 3, 2016 at 3:12
  • Since 3 and 4 have the same average rating. Any reason why number 3 is chosen over 4? Commented Sep 3, 2016 at 3:17
  • @SamuelToh I would like to have an array with each of the highest rating "number". Commented Sep 3, 2016 at 3:20
  • @westefan I have already gone through those 2 urls already, and both of them have different outcomes to what I am trying to do. Commented Sep 3, 2016 at 3:24

4 Answers 4

12
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
  }
}]
Sign up to request clarification or add additional context in comments.

Comments

1

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 } } ]

1 Comment

The OP's desired output includes filtering out duplicates, which is missing.
0

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);

Comments

0

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.

7 Comments

Sort functions need to return -1, 0, or 1, not a boolean.
@tor A boolean evaluates to true or false, 1 and 0, therefore I do not see a problem. Additionally, it works, and is essentially the same as the answers after it.
Please read the documentation for sort and the function to be passed to it. Returning the equivalent of 0 and 1 does work in some cases, but it does not work reliably.
@tor on both the w3schools.com/jsref/jsref_sort.asp and developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… sources, it has absolutely no mention of undefined behavior with booleans. When evaluating, it will check if true > 0, which will always return true.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.