skip to Main Content

I have an array of items that occur exactly twice, right next to eachother, like so:

const arr = ['1', '1', '2', '2', '3', '3']

I need to sort it in a different order, so all unique values occur first, and then their duplicates, like so:

const arr = ['1', '2', '3', '1', '2', '3']

How can I solve it by using sort() function? Or is there another way I can achieve this?

I tried something like this, but it didn’t work:

const sorted = myDublicatedArray.sort((left, right) => left.index - right.index);

5

Answers


  1. I can’t think of a way to do this only using Array.sort(). The approach below should work for both numeric and string inputs unless there are other requirements:

    const arrayWithDuplicates = ['1', '1', '2', '2', '3', '3'];
    // convert to a Set to get unique values
    const uniqueValues = new Set(arrayWithDuplicates);
    // sort by value
    const sortedArray = Array.from(uniqueValues).sort((a, b) => a - b);
    // duplicate the sorted array
    const arrayOrganized = [...sortedArray].concat(sortedArray);
    
    console.log(arrayOrganized)
    Login or Signup to reply.
  2. From comments I understand that you will have pairs of duplicate values following one after the other, never 3 or more of the same. In that case, you can map the input array like this:

    const arrayWithDuplicates = ['1', '1', '2', '2', '3', '3'];
    const result = arrayWithDuplicates.map((_, i, a) => a[i * 2 % a.length]);
    console.log(result);

    And if speed is a requirement, then go for an old-fashioned for loop:

    const arr = ['1', '1', '2', '2', '3', '3'];
    const result = [];
    for (let j = 0; j < 2; j++)
        for (let i = 0; i < arr.length; i += 2)
            result.push(arr[i]);
    console.log(result);
    Login or Signup to reply.
  3. You could maintain an index for every value and get a grouped array as first and then a flat array as result.

    const
        array = ['1', '1', '2', '2', '3', '3'],
        result = array
            .reduce((indices => (r, v) => {
                indices[v] ??= 0;
                (r[indices[v]++] ??= []).push(v);
                return r;
            })({}), [])
            .flat();
    
    console.log(result);
    Login or Signup to reply.
  4. If the values are already sorted and values are always present in sets of 2 you could use the following:

    const arr = ['1', '1', '2', '2', '3', '3'];
    const uniq = new Set(arr);
    const desired = Array.from({ length: 2 }).flatMap(() => Array.from(uniq));
    
    console.log(desired);

    The snippet above creates a Set uniq that contains all unique values in the array. To get the desired result we create an array with length 2 with Array.from(), then use flatMap() to fill and expand the array. We can use Array.from() to convert uniq from a Set to an array. The item order is based on insertion order ('1', then '2', then '3').

    If the amount of duplicates can be dynamic (but is the same across the whole array) you could make it more dynamic by using Array.from({ length: arr.length / uniq.size }). This would allow the following inputs:

    const arr = ['1', '2', '3'];
    const arr = ['1', '1', '1', '2', '2', '2', '3', '3', '3'];
    

    Note that the elements are still expected to be sorted and to be consistent in duplicate amount.

    Login or Signup to reply.
  5. You can use sort for this. First, map the elements to [element, occurrence] pairs. For example, the first occurrence of 2 is mapped to [2,0].

    Then, sort first by occurrence, and for elements with equal occurrence, sort by the element itself.

    Finally, extract just the element from the [element, occurrence] pair.

    const arr = ['1', '1', '2', '2', '3', '3']
    
    const result = Object.values(Object.groupBy(arr, e => e))
      .flatMap(arr => arr.map((e,i) => [e,i]))
      .sort(([a,i], [b,j]) => i-j || a-b)
      .map(([e]) => e)
    
    console.log(result)
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search