8

Say I have the following character array:

char[] c = new char[] { 'G', 'R', 'D', 'D', 'G', 'R', 'R', 'C', 'D', 'G', 'R', 'R', 'C', 'G', 'R', 'D', 'D', 'G', 'R', 'R', 'C', 'D', 'G', 'R', 'R', 'C' };


c.OrderBy(y => y).ForEach(x => Console.WriteLine(x));
//CCCCDDDDDDGGGGGGRRRRRRRRRR

How do I use LINQ to produce the following order?

//DDDDDDGGGGGGRRRRRRRRRRCCCC
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Matthew Layton
  • 39,871
  • 52
  • 185
  • 313

6 Answers6

37

Maybe you want to do something like this:

char [] customOrder = { 'D', 'G', 'R', 'C'};
char [] c = new char[] { 'G', 'R', 'D', 'D', 'G', 'R',
                         'R', 'C', 'D', 'G', 'R', 'R',
                         'C', 'G', 'R', 'D', 'D', 'G',
                         'R', 'R', 'C', 'D', 'G', 'R', 'R', 'C' };

foreach (char item in c.OrderBy(ch => Array.IndexOf(customOrder, ch))) {
    Console.Write(item);
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Perfect28
  • 11,089
  • 3
  • 25
  • 45
  • @TimSchmelter he is using ForEach LINQ extension method. – Euphoric Feb 26 '15 at 12:45
  • 1
    @Euphoric: there is no `ForEach` extension method apart from one that he might have written from the scratch. http://stackoverflow.com/a/200584/284240 – Tim Schmelter Feb 26 '15 at 12:47
  • @TimSchmelter https://msdn.microsoft.com/query/dev11.query?appId=Dev11IDEF1&l=EN-US&k=k(%22System.Collections.Generic.List%601.ForEach%22);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5);k(DevLang-csharp)&rd=true – BRAHIM Kamel Feb 26 '15 at 12:48
  • @KamelBRAHIM: that is not an extension method but an instance method of `List`. – Tim Schmelter Feb 26 '15 at 12:49
  • @TimSchmelter ok so you have such thing built-in it's not important an extension or an instance – BRAHIM Kamel Feb 26 '15 at 12:51
  • 1
    @KamelBRAHIM: no, but you have said that it's an extension method and it is not. It was there since .NET 2(so even before LINQ). It's important because OP uses `OrderBy(...).ForEach` and this answer used it also. Using `ToList().ForEach` is a bad habit because you are looping all items in the sequence to create a new collection from the scratch, just to enable to loop it again in `ForEach`. Use `foreach` if you want to loop(consume) a query. – Tim Schmelter Feb 26 '15 at 12:55
  • @TimSchmelter me?? :D are you sure ?? – BRAHIM Kamel Feb 26 '15 at 13:00
7

You could use another collection which defines the order:

char[] order = {'D','G','R','C'};
var customOrder = c.OrderBy(chr =>
{
    int index = Array.IndexOf(order, chr);
    if (index == -1) return int.MaxValue;
    return index;
});
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
5

If you want to define the order as relation between the items, then you have to use IComparer with the other OrderBy method.

public class Comparer : IComparer<char>
{
    public int Compare(Char a, Char b)
    {
       //return positive if a should be higher, return negative if b should be higher
    }
}

c.OrderBy(c => c, new Comparer()).ForEach(x => Console.WriteLine(x));
Euphoric
  • 12,645
  • 1
  • 30
  • 44
4

My own solution (thank you to those who led me in the right direction)

char[] c = new char[] { 'G', 'R', 'D', 'D', 'G', 'R', 'R', 'C', 'D', 'G', 'R', 'R', 'C', 'G', 'R', 'D', 'D', 'G', 'R', 'R', 'C', 'D', 'G', 'R', 'R', 'C' };
c.OrderBy(x => "CDRG".IndexOf(x)).ForEach(Console.Write);

Produces:

CCCCDDDDDDRRRRRRRRRRGGGGGG

Matthew Layton
  • 39,871
  • 52
  • 185
  • 313
2

You can use a dictionary with the order of the elements:

Dictionary<char, int> order = new Dictionary<char,int> {
    { 'D', 0 },
    { 'G', 1 },
    { 'R', 2 },
    { 'C', 3 },
};

char[] c = new char[] { 'G', 'R', 'D', 'D', 'G', 'R', 'R', 'C', 'D', 'G', 'R', 'R', 'C', 'G', 'R', 'D', 'D', 'G', 'R', 'R', 'C', 'D', 'G', 'R', 'R', 'C' };

// Here we search the dictionary for the "order" to be used
// and we compare the value with the value of the other 
// compared item
Array.Sort(c, (p, q) => order[p].CompareTo(order[q]));

var str = new string(c);
Console.WriteLine(str);
xanatos
  • 109,618
  • 12
  • 197
  • 280
2

I'd approach this with a join ensuring that the ordering array is on the left side of the join.

var ordering = "CDGR".ToCharArray();

var orderedOutput = ordering.Join(c, a => a, b => b, (a, b) => b);
spender
  • 117,338
  • 33
  • 229
  • 351