views:

263

answers:

3

I have a set of strings. I want to select all strings that contains another string. But I want to have as the first items, the items that start with the search, and then, alphabetically the other items. But the following code doesn't work:

items = items
   .Where(a => a.Contains(contained))
   .OrderBy(a => a)
   ;
var startsWith = items.Where(a => a.StartsWith(contained));
items = startsWith.Union(items.Except(startsWith));

What I have to do?

+5  A: 

Replace startsWith.Union with startsWith.Concat

Michael Donohue
+4  A: 

As well as Michael's option, you could also order by a Boolean:

items = items.OrderBy(x => !x.Contains(contained))
             .ThenBy(x => x);

Note that false sorts before true hence the ! here - you could also use a conditional to make it clearer:

items = items.OrderBy(x => x.Contains(contained) ? 0 : 1)
             .ThenBy(x => x);

Test program:

using System;
using System.Linq;

public class Test
{
    static void Main()
    {
        var items = new string[] { "the", "quick", "brown", "fox", 
                "jumps", "over", "the", "lazy", "dog" };

        var query = items.OrderBy(x => !x.Contains("o"))
                         .ThenBy(x => x);

        foreach (string word in query)
        {
            Console.WriteLine(word);
        }
    }
}

Output:

brown
dog
fox
over
jumps
lazy
quick
the
the
Jon Skeet
Heh. Beat me to it, with an example and all :)
lc
+2  A: 

You can use another OrderBy clause.

items = items.Where(a => a.Contains(contained))
   .OrderBy(a => a.StartsWith(contained) ? 0 : 1)
   .ThenBy(a => a);
lc