1

I'm trying to practice with arrays. Here are examples of what I want to achieve (let's keep it at array of 5 elements):

[3,5,8,1,3] => [3,3,8,5,1]
[1,5,2,2,5] => [5,5,2,2,1]
[7,5,5,5,5] => [5,5,5,5,7]
[1,5,7,2,3] => [7,5,3,2,1]

My attempt:

let myArr = [5,7,5,7,5];

function sortArr (arr) { 

  let sortedArr = [];
  let dupes = [];
  for (let i = 0; i <= arr.length-2; i++) {
    for (let j=i + 1; j <= arr.length-1; j++) {

      if (arr[i] == arr[j]) {
        if (sortedArr.some((element) => element == arr[i])) {
          sortedArr.push(arr[j]);
          dupes.push(j);
        } else {
          sortedArr.push(arr[i], arr[j])};
          dupes.push(j);
      }
      
    }
  }
  return sortedArr;
}
yunzen
  • 32,854
  • 11
  • 73
  • 106
  • 4
    *"... trying to practice with arrays"* where is your code? – Nina Scholz Sep 03 '20 at 13:49
  • 1
    Welcome to Stack Overflow! Please take the [tour] (you get a badge!) and read through the [help], in particular [*How do I ask a good question?*](/help/how-to-ask) Your best bet here is to do your research, [search](/help/searching) for related topics on SO, and give it a go. ***If*** you get stuck and can't get unstuck after doing more research and searching, post a [mcve] of your attempt and say specifically where you're stuck. People will be glad to help. – T.J. Crowder Sep 03 '20 at 13:51
  • By making a first pass, counting the number of occurances for each value. Then sort by `occurances[value] > 1` in descending order. – Thomas Sep 03 '20 at 13:51
  • Also, how should the non-duplicate entries be ordered? Original order preserved? How should the duplicates be ordered when there's more than one duplicate? (`[1, 2, 1, 2, 3]`, for instance.) Can you rely on ES2019's change requiring that `sort` on an array be stable? – T.J. Crowder Sep 03 '20 at 13:51
  • you can have a look here (just change the order of the first part): https://stackoverflow.com/questions/58730313/how-to-sort-an-array-efficiently/58730409#58730409 – Nina Scholz Sep 03 '20 at 13:55
  • See here https://codepen.io/HerrSerker/pen/jOqaErV?editors=0011 – yunzen Sep 03 '20 at 14:03

2 Answers2

1

First accumulate with Array#reduce an object where for every value in the array is one property with all it's occurences.
From this I get the values (e.g. [3,3]) and Array#sort them with a custom comperator. Here I first look for the length of the arrays which are compared. If both are same compare the values otherwise array with more lements are first.
At last I use Array#flat to flat the array and I have the desired result.

For trying: https://jsfiddle.net/7p8wt4km/4/

function mySort(arr) {
  return  Object.values(arr.reduce((acc,cur) => {
      if (!acc[cur])
          acc[cur]=[cur];
      else
          acc[cur].push(cur);
      return acc;
  },{})).sort((a,b) => {
      lenA = a.length;
      lenB = b.length;
      return (lenA !== lenB) ? lenB- lenA : b[0] - a[0];
  }).flat();
}

console.log(mySort([3,5,8,1,3])); // [3,3,8,5,1]
console.log(mySort([3,5,8,1,3])); // [5,5,2,2,1]
console.log(mySort([7,5,5,5,5])); // [5,5,5,5,7]
console.log(mySort([1,5,7,2,3])); // [7,5,3,2,1]
console.log(mySort([1,5,2,2,7,2,7,2,5,3])); // [2, 2, 2, 2, 7, 7, 5, 5, 3, 1]

// This will work too
console.log(mySort([Number.MAX_SAFE_INTEGER,5,5,7,7,7,3, Number.MAX_SAFE_INTEGER,3,3,3,2,2,2,1]));
console.log(mySort([.00001,.00005,.00007,.00002,.00003,.00003,.00003]));
Sascha
  • 4,576
  • 3
  • 13
  • 34
  • I check with this "if-block" if the accumulated object `acc` has a falsy value for the property with key `cur`. I don't want to check if it's value is not equal to 0. But this condition is also true if there doesn’t exists any such key (because `!undefined` is `true`) in the object. If you want you could use the condition `(!acc.hasOwnProperty(cur))` instead. I check this because if this property doesn’t exist I create it with an array with the current data inside it as value. On the other hand if it exists already then I had only to push the current data to the array in this property. – Sascha Sep 10 '20 at 14:21
  • By this I could accumulte an object with all the values of your array and each property includes all the values with this name. These properties then I can use for the sorting. – Sascha Sep 10 '20 at 14:24
  • `sort((a, b) => b.length - a.length || b[0] - a[0])` – Thomas Sep 28 '20 at 09:46
1

Array.prototype.sort() can have a compare function as parameter.

I first count the occurrences with Array.prototype.reduce(). then I sort by comparing the count and the value of the entries

console.clear();

function sortArray(arr) {
  "use strict";
  
  var counts = arr.reduce((carry, elem) => {
    carry[elem] = ( carry[elem] || 0 ) + 1;
    return carry;
  }, {})
  return arr.sort((a, b) => (counts[b] == counts[a]) ? b - a : counts[b] - counts[a]);
}
console.log(sortArray([3,5,8,1,3]))
console.log(sortArray([1,5,2,2,5]))
console.log(sortArray([7,5,5,5,5]))
console.log(sortArray([1,5,7,2,3]))

console.log(sortArray([Number.MAX_SAFE_INTEGER,5,5,7,7,3, Number.MAX_SAFE_INTEGER,3,3,3,2,2,2,1]))
console.log(sortArray([.00001,.00005,.00007,.00002,.00003,.00003,.00003]))
yunzen
  • 32,854
  • 11
  • 73
  • 106
  • This is a clever way by multiplying with `1E6` to shorten the sorting algorithm but this will only work as long as the values in the array are not too big. If you want allways to be on the **secure** site use `(counts[a] !== counts[b]) ? counts[b] - counts[a] : b - a;` like I have done in my sollution. – Sascha Sep 03 '20 at 14:25
  • 1
    @Sascha You are absolutely correct – yunzen Sep 03 '20 at 14:46
  • `sort((a, b) => counts[b] - counts[a] || b - a)` – Thomas Sep 28 '20 at 09:45