0

so I have a list of numbers and color values.

[1, Red]
[4, Yellow]
[5, Red]
[6, Yellow]
[8, White]
[9, Red]
[10, Yellow]
[13, White]
etc. etc.

The dictionary ints are originally generated randomly within a range between 1 - 100 using Enumerable. var lstNumbers = Enumerable .Range(1, 100).OrderBy(n => Guid.NewGuid().GetHashCode()) .ToList();

The dictionary is created and used to assign ColorType Values to each of the numbers in Sequence Red, Yellow, White, Red, Yellow, White, etc., etc. to all of the numbers in the list.var map = new Dictionary<int, ColorType>();

I then Remove items a few different ways which brings me to the sorting. I need to sort the final list from this dictionary by value with White results being at the top, Yellow in the middle, and red at the bottom. Red < Yellow < White

Then display.

I figured I could use some if statements for sequencing the colors or maybe setting parameters for each color then use Orderby in a way to sort the results by the color value.

I'm having a hard time figuring out the efficient way of sorting these particular values in this way.

Any ideas?

  • Possible duplicate of [How can I sort (Custom Sort) list of Dictionary entry by value](https://stackoverflow.com/questions/36685446/how-can-i-sort-custom-sort-list-of-dictionary-entry-by-value) – raichiks Apr 06 '18 at 08:39
  • You know that a dictionary isnt sorted? – Tim Schmelter Apr 06 '18 at 08:42
  • 1
    You can do something like `dict.OrderBy(c => c.Value == "White" ? 0 : c.Value == "Yellow" ? 1 : 2)`. Just don't put results back into dictionary, since dictionary is unordered structure. Put them into `List` or something like that. – Evk Apr 06 '18 at 08:46
  • @raichiks I tried to see if that could help but I have 100 Key ints so unless I want to make 100 Data values to go with it I don't think that duplicate post would help. The should be a more efficient way right? – Justeasy StackAttacka Apr 07 '18 at 02:34
  • @Evk I tried that OrderBy but I may have not implemented it correctly or it might not work for my scenario because I get and error where the == operator can not be applied to operands of 'ColorType' and 'string'. `foreach (var color in map.OrderBy(c => c.Value == "White" ? 0 : c.Value == "Yellow" ? 1 : 2)) { Console.WriteLine(color); }` – Justeasy StackAttacka Apr 07 '18 at 04:01

3 Answers3

1

Here's an implementation based on this answer:

public class CustomerComparer : IComparer<KeyValuePair<int, string>>
{
    private List<string> orderedColors = new List<string>() { "White", "Yellow", "Red" };

    public int Compare(KeyValuePair<int, string> str1, KeyValuePair<int, string> str2)
    {
        return orderedColors.IndexOf(str1.Value) - orderedColors.IndexOf(str2.Value);
    }
}

class Program
{
    static void Main(string[] args)
    {
        var unsorted = new Dictionary<int, string>()
        {
            {1, "Red"},
            {4, "Yellow"},
            {5, "Red"},
            {6, "Yellow"},
            {8, "White"},
            {9, "Red"},
            {10, "Yellow"},
            {13, "White"}
        };

        var sorted = unsorted.OrderBy(x => x, new CustomerComparer());

        foreach (var entry in sorted)
        {
            Console.WriteLine("{0}: {1}", entry.Key, entry.Value);
        }
        Console.ReadKey();
    }
}

You can take a look at this article.

Update

Based on comments on this answer, the value for which order the dictionary seems to be a number which comes from a Enum.

Updated code:

public class CustomerComparer : IComparer<KeyValuePair<int, ColorType>>
{
    private List<ColorType> orderedLetters = new List<ColorType>() { ColorType.White, ColorType.Yellow, ColorType.Red };

    public int Compare(KeyValuePair<int, ColorType> str1, KeyValuePair<int, ColorType> str2)
    {
        return orderedLetters.IndexOf(str1.Value) - orderedLetters.IndexOf(str2.Value);
    }
}

public enum ColorType
{
    Red,
    Yellow,
    White
}

class Program
{
    static void Main(string[] args)
    {
        var unsorted = new Dictionary<int, ColorType>()
        {
            {1, ColorType.Red},
            {4, ColorType.Yellow},
            {5, ColorType.Red},
            {6, ColorType.Yellow},
            {8, ColorType.White},
            {9, ColorType.Red},
            {10, ColorType.Yellow},
            {13, ColorType.White}
        };

        var sorted = unsorted.OrderBy(x => x, new CustomerComparer());

        foreach (var entry in sorted)
        {
            Console.WriteLine("{0}: {1}", entry.Key, entry.Value);
        }
        Console.ReadKey();
    }
}
Omar Muscatello
  • 1,256
  • 14
  • 25
  • This looks like it would almost get me there but I ran into a problem because I am using a custom type in my dictionary that I use for the colors. Where I assign each of the Enum key ints Color Values Red, White, Yellow, Red, White, Yellow, etc., etc. and goes throughout all of the randomized numbers ranging 1 - 100. `public static ColorType Next(this ColorType color) { if (color == ColorType.Red) return ColorType.Yellow; if (color == ColorType.Yellow) return ColorType.White; return ColorType.Red; }` – Justeasy StackAttacka Apr 06 '18 at 22:19
  • So when I try to convert it to a string in the return statement in the compare method I get an error because it cant convert it to a string. – Justeasy StackAttacka Apr 06 '18 at 22:26
  • Please, show your custom type code so I can help you. – Omar Muscatello Apr 07 '18 at 08:49
  • `public enum ColorType { Red, Yellow, White } public static class ColorExtension { // Iterator for lstNumbers Enumerable public static ColorType Next(this ColorType color) { if (color == ColorType.Red) return ColorType.Yellow; if (color == ColorType.Yellow) return ColorType.White; return ColorType.Red; }` – Justeasy StackAttacka Apr 07 '18 at 19:01
  • `internal class Program { public static void Main(string[] args) { // Creating numbers ranging from 1 - 100 and randomizing var lstNumbers = Enumerable .Range(1, 100).OrderBy(n => Guid.NewGuid().GetHashCode()) .ToList(); // Start point for color assignment var startColor = ColorType.Red; var map = new Dictionary();` – Justeasy StackAttacka Apr 07 '18 at 19:06
  • `foreach (var number in lstNumbers) { // First color for assignment map[number] = startColor.Next(); // Advance the color startColor = startColor.Next(); }` – Justeasy StackAttacka Apr 07 '18 at 19:08
  • `foreach (KeyValuePair entry in map.ToList()) { if (entry.Key % 2 == 0 && entry.Value == ColorType.Red) { map.Remove(entry.Key); } if (entry.Key % 2 == 1 && entry.Value == ColorType.Yellow) { map.Remove(entry.Key); } if (entry.Key % 3 == 0 && entry.Value == ColorType.White) { map.Remove(entry.Key); } }` – Justeasy StackAttacka Apr 07 '18 at 19:17
  • `foreach (var number in map.OrderBy(i => i.Key)) { Console.WriteLine(number); } Console.ReadLine();` – Justeasy StackAttacka Apr 07 '18 at 19:22
0

Here's a hint:

Red = 100
Yellow = 110
White = 111

(Just to say that the color order you want is already implicit by the RGB values of the colors you mentioned. So it should be a good source for a order-value.)

Andreas Zita
  • 7,232
  • 6
  • 54
  • 115
0

You can use Enum, to sort colors that suit your needs. If identifier is just a string value, you have to find by string value and convert it to int value. If there will be more colors in future, or order will have to change, just modify Enum. Of course need to update, if color is not found in Enum, but that is not the case to add for this question...

 public enum ColorCodes
{
    White = 1,
    Yellow = 2,
    Red = 3
}

class Program
{
    /// <summary>
    /// Sorts dictionary by color enum int sequence
    /// </summary>
    /// <param name="toOrder"></param>
    /// <returns></returns>
    public static Dictionary<int, string> DictionarySorter(Dictionary<int, string> toOrder)
    {
        return toOrder.OrderBy(x => (int)(ColorCodes)Enum.Parse(typeof(ColorCodes), x.Value)).ToDictionary(x => x.Key, x => x.Value);
    }


    static void Main(string[] args)
    {

        Dictionary<int, string> unsortedColors = new Dictionary<int, string>();
        unsortedColors.Add(1, "Red");
        unsortedColors.Add(4, "Yellow");
        unsortedColors.Add(5, "Red");
        unsortedColors.Add(6, "Yellow");
        unsortedColors.Add(8, "White");
        unsortedColors.Add(9, "Red");
        unsortedColors.Add(10, "Yellow");
        unsortedColors.Add(13, "White");


        var sortedDic = DictionarySorter(unsortedColors);
        foreach (var entry in sortedDic)
        {
            Console.WriteLine(string.Format("{0} - {1}", entry.Key, entry.Value));
        }
        Console.Read();
    }
}

As others pointed out -dictionary is not sorted in order, so inplace of Dictionary sorter can use:

 public static List<KeyValuePair<int,string>> DictionarySorter(Dictionary<int, string> toOrder)
    {
        return toOrder.OrderBy(x => (int)(ColorCodes)Enum.Parse(typeof(ColorCodes), x.Value)).ToList();
    }
raichiks
  • 286
  • 4
  • 16
  • This could possibly work too. The types I have for the Dictionary are int, ColorType. Which is a custom type that I use to assign the colors in a specific order earlier in the program to a list of random numbers that range from 1 - 100. `public static ColorType Next(this ColorType color) { if (color == ColorType.Red) return ColorType.Yellow; if (color == ColorType.Yellow) return ColorType.White; return ColorType.Red; }` – Justeasy StackAttacka Apr 07 '18 at 02:17
  • Here is my Dictionary: `var map = new Dictionary();` – Justeasy StackAttacka Apr 07 '18 at 02:19
  • Than you can change a Dictionary sorter method to `public static List> DictionarySorter(Dictionary toOrder) { return toOrder.OrderBy(x => (int)(ColorCodes)Enum.Parse(typeof(ColorCodes), x.Value.ToString())).ToList(); }` – raichiks Apr 11 '18 at 13:17
  • and then resort your Dictionary called "map" `var sortMyDic = DictionarySorter(map); foreach (var number in sortMyDic) { Console.WriteLine(number); } Console.ReadLine();` – raichiks Apr 11 '18 at 13:20
  • or just use your own enum, if by default color order is as needed `public static List> DictionarySorter(Dictionary toOrder) { return toOrder.OrderBy(x => (int)x.Value).ToList(); }` this came out as good solution and get rid of my enum, and just saw this, If you posted your code in question from beginning – raichiks Apr 11 '18 at 13:28
  • *as enum auto increase its int value (starting 0), if it is not defined. Your enum `public enum ColorType { Red, Yellow, White }` is same, if it was defined this way : `public enum ColorType { Red=0, Yellow=1, White=2 }` – raichiks Apr 11 '18 at 13:55
  • one more comment, if random int key is affecting order too, than can add `ThenBy()` example. order by color(enum of dictionary) and then by generated int value(key of your dictionary), - `return toOrder.OrderBy(x => (int)x.Value).ThenBy(x=>x.Key).ToList();` – raichiks Apr 11 '18 at 14:02