Home > Blockchain >  Sorting an array by another array's values using OrderByDescending() does not sort the array
Sorting an array by another array's values using OrderByDescending() does not sort the array

Time:11-11

I'm trying to implement a simple Huffman coding algorithm. I take my input string (ddddbbcccaeeeee) and use it to create 2 arrays, those being a char array called usedCharacters and an int array called characterCounts. However these arrays need to be sorted by the number of times the character appears in the input string so the Huffman tree can be constructed. I tried using LINQ's OrderByDescending() method like I had seen online:

usedCharacters = usedCharacters.OrderByDescending(i => characterCounts).ToArray();
characterCounts = characterCounts.OrderByDescending(i => i).ToArray();

The program runs but when I check the results the characters are very obviously still in order as they appear in the input string, meaning no sorting is actually done. On the other hand, characterCounts does succesfully sort. I also tried the more commonly seen online solution of usedCharacters.OrderByDescending(i => characterCounts.IndexOf(i)).ToArray() but that just causes an index out of bounds exception for reasons I don't fully understand. If anybody could give me some insight into what I'm missing that would be greatly appreciated. Thank you!

CodePudding user response:

The simplest way to achieve what you're trying to do is to use a GroupBy expression.

  var s = "ddddbbcccaeeeee";
  
  var list = s.GroupBy(x => x)
              .Select(x => new { Char = x.Key, Count = x.Count() })
              .OrderByDescending(x => x.Count);

  foreach(var item in list)
  {
      Console.WriteLine(item.Char   " "   item.Count);
  }

The code treats s as a character array and counts instances of all characters. The OrderByDescending then sorts by Count.

The output of code below should look something like this:

e 5
d 4
c 3
b 2
a 1

CodePudding user response:

Your LINQ statement is trying to sort each element in usedCharacters by an by a constant int[]. It doesn't do anything like matching up the elements of both arrays. It's exactly as if you are doing this:

usedCharacters = usedCharacters.OrderByDescending(i => 42).ToArray();

It just leaves the array in the same order.

If you have two separate list and you want to order the first based on the second then you need to use Zip like this:

usedCharacters =
    usedCharacters
        .Zip(characterCounts)
        .OrderByDescending(x => x.Second)
        .Select(x => x.First)
        .ToArray();

If you have the initial string of characters then this is the simplest way to get your result:

string characters = "ddddbbcccaeeeee";
char[] usedCharacters =
    characters
        .GroupBy(x => x)
        .OrderByDescending(x => x.Count())
        .Select(x => x.Key)
        .ToArray();
  • Related