-1

I have a single 1d array storing a series of scores. My end goal is to have the 5 highest scores with brackets around them ( e.g. (score) ) for me to then format and output onto the display. In the case where there are duplicate scores, the first occurrences would be bracketed, up to that 5 top values.

So for example: [9,8,10,9,6,8,6,5,4,4,3,3,6] would become [(9),(8),(10),(9),6,(8),6,5,4,4,8,3,8]

What I've tried so far is this:

var topvals = scores.sort((a,b) => b-a).slice(0,5);
    for(var j=0; j< scores.length; j++){
      if(topvals.length==0){
        break;
      }else if(topvals.includes(scores[j])){
        scores[j] = "(" + scores[j] + ")";
        topvals.splice(topvals.indexOf(scores[j]),1);
      }
    }

With the idea that topvals is an array containing the top 5 values, and I then loop through scores looking for those values, removing them each time.

What this results in is the first 5 values of scores having brackets around them.

I'm happy to go a completely different route with this, or just fix what I've done so far. Thanks in advance.

Dan Bard
  • 3
  • 3
  • just clone scores. scoreclone = scores.slice() – user120242 Jun 22 '20 at 15:25
  • Does this answer your question? [Keep original array after JavaScript function](https://stackoverflow.com/questions/19169873/keep-original-array-after-javascript-function) – user120242 Jun 22 '20 at 15:26
  • Unfortunately not. That post only deals with editing the array where you know where the values are. The problem I have is what is described in the text of the post. – Dan Bard Jun 22 '20 at 20:12
  • Should `dvals` in your example be `topvals`? Also can you explain what error / unexpected behavior you are having? – Ian Wilson Jun 22 '20 at 20:24
  • How efficient does this need to be? Easiest way is to just `scores.map((n,i)=>({n,i})).sort((a,b)=>b.n-a.n).slice(0,5).map(({i})=>i).forEach(i=>scores[i]=\`(${scores[i]})\`)`. If you need O(N) for large data sets, you can do a pivot algorithm. – user120242 Jun 22 '20 at 20:25
  • Your example doesn't match your description, both `8`s are surrounded by braces. Did you only mean the first 8 to be braced? Because you say `... the first occurrence would be bracketed`. Also your code contains a few errors `scores[i][j]` should be `scores[j]` and it seems that `dvals` should be `topvals`. – Ian Wilson Jun 22 '20 at 20:37
  • @IanWilson Sorry, you're right on the first bit, this is coming out of a much bigger project so was trying to change some variables to make sense on their own. No, the second 8 should be braced as well. The top 5 values are 10,9,9,8,8 so the first two 8s should be braced, but not the third. Does that explain it better? – Dan Bard Jun 23 '20 at 10:31
  • Yes, that makes sense now. Funny how things can be interpreted. But also the lists do not seem to be the same list. The last 3 digits of the original list are `3,3,6` and the last 3 digits of the formatted list are `8,3,8`. – Ian Wilson Jun 23 '20 at 20:37

2 Answers2

0

The call to sort() sorts scores in place, which means it changes the scores array. So that is why you need to clone it first, then sort, then slice. Also you probably want to eliminate duplicates from your scores. I linked a stack overflow answer that describes how to do that. Since filter does not filter scores in place, but rather returns a new array, you don't need to explicitly call slice(0) to clone scores.

var scores = [9,8,10,9,6,8,6,5,4,4,3,3,6];

// Function from linked SO answer.
function onlyUnique(value, index, self) { 
    return self.indexOf(value) === index;
}

// Filter unique scores into copy of array, then slice the top 5.
var topvals = scores.filter(onlyUnique).sort((a,b) => b-a).slice(0,5);

for (var j=0; j< scores.length; j++) {
   if( topvals.length==0) {
        break;
   } else if(topvals.includes(scores[j])) {
        scores[j] = "(" + scores[j] + ")";
        topvals.splice(topvals.indexOf(scores[j]),1);
   }
}

Get all unique values in a JavaScript array (remove duplicates)

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Ian Wilson
  • 6,223
  • 1
  • 16
  • 24
  • The problem with this is that I need to keep the duplicates. The question stems from the very end of a bigger project where I just need to do some formatting before output so the data needs to be kept exactly as is. – Dan Bard Jun 23 '20 at 10:42
0

sort with indexes attached. Use index positions to change to desired format. O(N log N) for the sort.

scores = [9,8,10,9,6,8,6,5,4,4,3,3,6]
scores.map((n,i)=>({n,i})) // each object as n: number, i: index
  .sort((a,b)=>a.n-b.n).slice(-5) // sort, slice top 5
  .forEach(({i})=>scores[i]=`(${scores[i]})`) // add parens by indexes

console.log(scores)

If you have very, very large data sets and need something closer to O(N), you'll want to implement a pivot selecting algorithm. Just sorting is simpler.

user120242
  • 14,918
  • 3
  • 38
  • 52
  • Thank you, sorting with indexes attached should work for this exactly. I had been bashing my head against the wall in one particular direction for a while so couldn't see other routes to take! – Dan Bard Jun 23 '20 at 10:39