tags:

views:

329

answers:

4

I can think of a million ways to do this, but none seem very elegant. I wonder if anyone knows a neat way to move an item of say id=10 as the first item in a list using LINQ (or whatever really)

Item A - id =5
Item B - id = 10
Item C - id =12
Item D - id =1

In this case how can I elegantly move Item C to the top of my List?

This is the best I have right now...

        var allCountries = repository.GetCountries();
        var topitem = allCountries.Single(x => x.id == 592);

        var finalList = new List<Country>();
        finalList.Add(topitem);
        finalList = finalList.Concat(allCountries.Where(x=> x.id != 592)).ToList();
+5  A: 

LINQ is strong in querying collections, creating projections over existing queries or generating new queries based on existing collections. It is not meant as a tool to re-order existing collections inline. For that type of operation it's best to use the type at hande.

Assuming you have a type with a similar definition as below

class Item {
  public int Id { get; set; }
  ..
}

Then try the following

List<Item> list = GetTheList();
var index = list.FindIndex(x => x.Id == 12);
var item = list[index];
list[index] = list[0];
list[0] = item;
JaredPar
+1 Works well for the swap scenario, I gotta feelin' that a rotate is actually required tho'
AnthonyWJones
This is more or less what i did any way, but thanks for the explanation as to why there is seemingly not a better way :)
qui
+3  A: 

Linq generallyworks on Enumerables, so it doesn't now that the underlying type is a collection. So for moving the item on top of the list I would suggest using something like (if you need to preserve the order)

var idx = myList.FindIndex(x => x.id == 592);
var item = myList[idx];
myList.RemoveAt(idx);
myList.Insert(0, item);

If your function returns only an IEnumerable, you can use the ToList() method to convert it to a List first

If you don't preserve the order you can simply swap the values at position 0 and position idx

Grizzly
This is perfect for the rotate down scenario instead of just swapping the values.
Bradley Mountford
+1  A: 

What do you want to order by, other than the known top item? If you don't care, you can do this:

var query = allCountries.OrderBy(x => x.id != 592).ToList();

Basically, "false" comes before "true"...

Admittedly I don't know what this does in LINQ to SQL etc. You may need to stop it from doing the ordering in the database:

var query = allCountries.AsEnumerable()
                        .OrderBy(x => x.id != 592)
                        .ToList();
Jon Skeet
A: 

Here is an extension method you might want to use. It moves the element(s) that match the given predicate to the top, preserving order.

public static IEnumerable<T> MoveToTop(IEnumerable<T> list, Func<T, bool> func) {
    return list.Where(func)
               .Concat(list.Where(item => !func(item)));
}

In terms of complexity, I think it would make two passes on the collection, making it O(n), like the Insert/Remove version, but better than Jon Skeet's OrderBy suggestion.

configurator