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();