1

I have the array of strings that I want to sort in a custom order My array looks like this

["E", "D", "CC", "C", "B", "BB", "BBA", "BBD", "BBE", "BBB", "BBBC", "A", "AA"]

In my sorted array I want to show the words alphabetically but the words with large number of continuous letter should appear first.

If more number of words have same length of continuous letter then need to consider next letter alphabetically.

My expected result should look like this

["AA", "A","BBBC", "BBB","BBA", "BBD", "BBE", "BB", "B", "CC", "C", "D", "E"]

I tried to sort using the default sort() function but it didn't give me expected results. So please give your suggestions

9
  • 2
    .sort() can have a callback function as argument to be used as a comparer of 2 elements. You can write your sorting rule there Commented Jan 18, 2022 at 5:53
  • 2
    Where would BBA go? Commented Jan 18, 2022 at 5:58
  • @JMP I have edited the question based on your question. Hope it helps to understand my query Commented Jan 18, 2022 at 6:10
  • 1
    How can you sort BBA, BBD, BBE, BBB to be BBB, BBA, BBD, BBE? Surely it should be BBA, BBB, BBD, BBE? Or does it depend on how the elements are stored in the original array? Or are elements with all the same character somehow worth more? Commented Jan 18, 2022 at 6:31
  • 1
    Does BBAA come before BBAB? Commented Jan 18, 2022 at 7:19

4 Answers 4

2

Ok, this should do what you want. It takes into consideration the length of the string, and whether all characters are the same and finally sorts by alpha after that:

let rawArray = ["E", "D", "CC", "C", "B", "BB", "BBA", "BBD", "BBE", "BBB", "BBBC", "A", "AA"];

rawArray.sort((a,b) => {
  
  if (a.substring(0, 1) === b.substring(0, 1) && allEqual(a) && !allEqual(b)) {
    return -1
  } 
  else if (a.length > b.length){
    return -1
  }
  else if (a < b && !allEqual(a + b)){
    return -1
  }
    
  else {
    return 1
  }
    
});


function allEqual(input) {
  
    return input.split('').every(char => char === input[0]);
}

console.log(rawArray); //["AA", "A", "BBBC", "BBB", "BBA", "BBD", "BBE", "BB", "B", "C", "CC", "D", "E"]

I made use of another answer to get the allEqual function. You can find that here.

You could also shorten the sort function, but it makes it less readable:

rawArray.sort((a,b) =>   
  (a.substring(0, 1) === b.substring(0, 1) && allEqual(a) && !allEqual(b))
              ||
              (a.length > b.length)
              ||
              (a < b && !allEqual(a + b))
              ? -1 : 1    
);
Sign up to request clarification or add additional context in comments.

2 Comments

I am getting output like [ "AA", "A", "BBBC", "BBB", "BBA", "BBD", "BBE", "BB", "B", "C", "CC", "D", "E" ] but expected one is [ "AA", "A", "BBBC", "BBB", "BBA", "BBD", "BBE", "BB", "B", "CC", "C", "D", "E" ] Note the letter C.
Ok, that should be fixed now.
2

I'd first write a function that compares 2 elements with the expected rules and returns 1 if the first element should be first, else -1, check the length of the 2 elements and see if the longest starts with the smallest (like in "AAA" and "A")

function myComparer(a, b)
{
  if (a.length < b.length)
  {
    if (b.startsWith(a))
    {
      return 1; // a should be after b
    }
  }
  else if (a.length > b.length)
  {
    if (a.startsWith(b))
    {
      return -1; // b should be after a
    }
  }

  if (a < b)
  {
    return -1;
  }
  return 1;
}

const CompareTester = (a, b) => {
  if (myComparer(a, b) == -1)
  {
    console.log(`"${a}" then "${b}"`);
  }
  else
  {
    console.log(`"${b}" then "${a}"`);
  }
}

const testArr = [
  { a: "AAA", b: "A" },
  { a: "A", b: "AAA" },
  { a: "BBA", b: "BB" },
  { a: "A", b: "B" },
  { a: "ABC", b: "DEF" },
  { a: "ABC", b: "ABCDEF" }
];

for (elem of testArr)
{
  CompareTester(elem.a, elem.b);
}

Now, you can use this function as a callback for the .sort() method :

const arr = ["E", "D", "CC", "C", "B", "BB", "BBA", "BBD", "BBE", "BBB", "BBBC", "A", "AA"];

function myComparer(a, b)
{
  if (a.length < b.length)
  {
    if (b.startsWith(a))
    {
      return 1; // a should be after b
    }
  }
  else if (a.length > b.length)
  {
    if (a.startsWith(b))
    {
      return -1; // b should be after a
    }
  }

  if (a < b)
  {
    return -1;
  }
  return 1;
}

arr.sort(myComparer);

console.log(arr);

4 Comments

This one returns: ["AA", "A", "BBA", "BBBC", "BBB", "BBD", "BBE", "BB", "B", "CC", "C", "D", "E"] instead of ["AA", "A","BBBC", "BBB","BBA", "BBD", "BBE", "BB", "B", "CC", "C", "D", "E"] though.
@JimJimson can you reduce your example so I can see what you mean?
According to the OP, BBB needs to come first, then BBA, not BBA first and then BBB after. It's a very, very weird requirement! I gave you an upvote for effort though haha
I see, could be a typo in OP example, because "AA" and "AAA" are just supposed to be string samples
2

The challenge was understanding the sort rules implicit in the question, but I think I can restate the OP to suggest that the strings should be sorted first by the lexical order of the first letter, then by the run length of the first set of repeating characters, then by the whole string length, and last by the lexical order of the remaining chars.

To expose that logic clearly in the sort, This snippet preprocesses the input strings into objects like:

{ input: "BBBC", firstChar: "B", runLength: 3, fallback: "C", length: 4 }

If all that's right, then the sort is simple...

function sortInfo(original) {
  const firstLetter = original[0];
  const length = original.length;
  let runLength = 0;
  for (let letter of original) {
    if (letter === firstLetter) runLength++;
    else break;
  }
  const fallback = original.slice(runLength)
  return {  original, firstLetter, runLength, length, fallback }
}

let input = ["E", "D", "CC", "C", "B", "BB", "BBA", "BBD", "BBE", "BBB", "BBBC", "A", "AA"];
let sortable = input.map(sortInfo)

sortable.sort((a,b) => {
  if (a.firstLetter !== b.firstLetter) return a.firstLetter.localeCompare(b.firstLetter);
  if (a.runLength !== b.runLength) return b.runLength - a.runLength;
  if (a.length !== b.length) return b.length - a.length;
  return a.fallback.localeCompare(b.fallback);
});

console.log(sortable.map(o => o.original))

4 Comments

I think the prefix rule must be done recursively. He did not answer to the question if AABB comes before AABA, but I think this must be so.
AABA comes before AABB. Length first (BBBC), then all same letter followed by alpha sort (BBB, BBA, BBC, BBD)
Yeah, @JimJimson, dunno. I'm still not sure about the OP intent. My aim was to expose a useful way of articulating the problem. Cheers.
@ceving, I see, so it would be first letter, then length of the first repeating string, then recursively on the remainder. That's interesting. New website idea: "overflowstack"... people post answers, and other people try to work out what the question is. :-)
2

You need your own custom sorting algorithm for this kind of sorting.

var yourArray = ["E", "D", "CC", "C", "B", "BB", "BBB", "A", "AA"];  // Unsorted Array  

let customerSort = (arr) => 
{
    // This loop is for iterating array
    for (var i = 0; i < arr.length; i++) 
    {   
        // This loop is for comparing each item of the array with all items in array
        for (var j = 0; j < arr.length; j++)
        {
            // This condition is for sorting array in alphabetical order
            if (arr[i] < arr[j]) 
            {
                var x = arr[i];
                arr[i] = arr[j];
                arr[j] = x; 
            }

            // This condition is for sorting array in the custom order needed
            if (arr[i].charAt(0) == arr[j].charAt(0) && arr[i].length > arr[j].length) 
            {
                var x = arr[i];
                arr[i] = arr[j];
                arr[j] = x; 
            }
        }
    }
    // Return Sorted Array
    return arr;
}

console.log(customerSort(yourArray));

3 Comments

Close. But this also produces the incorrect result: ["AA", "A", "BBBC", "BBA", "BBB", "BBD", "BBE", "BB", "B", "CC", "C", "D", "E"] vs ["AA", "A", "BBBC", "BBB", "BBA", "BBD", "BBE", "BB", "B", "CC", "C", "D", "E"]
Is the length of the string a consideration while sorting
Is BBB the only exception

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.