views:

115

answers:

4

In .NET, the Generics Lists have a sort function that accepts IComparer or Comparison. I'd like to sort just part of a list. Hopefully I can specify the start index, count of elements to sort, and a lambda function. It looks like you can only use lambda functions to do this if you're sorting the entire list. Is that right or did I miss something?

Additional Requirements:

  • Sort in place (to save memory/time)
  • Final list has the same length as the original list
A: 

If you can find a way to make use of some filter tools with the list or linq methods you can. Here is an example using the FindAll.

genericList = genericList.FindAll(x => x.Field).OrderBy(y => y.Field).ToList();
Dustin Laine
@I don't think this quite does what Eyal wants. `FindAll` could (and there's no reason it wouldn't) return a spread-out assortment of items from the collection, not within any particular (indexed) range.
Dan Tao
+1  A: 
List<int> mylist = new List<int>() {8,4,6,2,1,5,3,1,7};
List<int> myRange = mylist.GetRange(2,4);

mylist.RemoveRange(2, 4);
mylist.InsertRange(2,  myRange.OrderBy(i => i));

mylist.Dump();

EDIT: Think of Dump as running a foreach on the list & printing it to the console.
And this is changing the content of the original list.

EDIT2: See if this code helps at all

    List<int> mylist = new List<int>() ;
    for(int i=9999999; i > 0; i--)
    {
        mylist.Add(i);
    }

    Console.WriteLine("start " + DateTime.Now.Ticks);
    var extract = mylist.Skip(10).Take(1000000).OrderBy(i => i);

    int k = 10; // start from (because we skipped from 10 onwards above)
    foreach(int item in extract)
    {
        mylist[k++] = item;
    }


    Console.WriteLine("done" + DateTime.Now.Ticks);
    foreach(int item in mylist)
        Console.WriteLine(item);
shahkalpesh
I tried this but it's very slow due to the RemoveRange and InsertRange operations.
Eyal
@Eyal: How big is the list?
shahkalpesh
5million elements. I'm doing something similar to QuickSort. I need to partition the list and then sort each subpartition except at each level the comparison function changes.
Eyal
In the end, I implemented my own QuickSort that takes start and end index as arguments. Anything using Take,Remove,AddRange,RemoveRange, etc was just too slow. It sounds inelegant but the process now completes in 30 minutes (down from 24 hours).
Eyal
A: 

Do you have a requirement that the list needs to still have all items after this, or will you only be working on the subset that is ordered? If the latter then you can use regular Linq to do this - something like this might work for you.

IEnumerable<T> enumerable = GetTheListToWorkWith();
IEnumerable<T> sortedStuff = enumerable.Skip(startIndex).Take(endIndex).OrderBy(t => t.ValueToCompare);

This method will not change the original list however - it will just return a new IEnumerable that has only the sorted portion of the List.

As an alternate (if all data needs to remain in the list you could remove the subset that needs to be sorted, sort it then reattach it to the original list

saret
Sorry only saw after I answered that you wanted a VB answer (should be similar to what I posted...)
saret
Nope, I need the whole list returned.
Eyal
+1  A: 

Instead of RemoveRange and InsertRange you could extract the sublist, and the copy it back. Yes, I know, this isn’t in-place either but short of rewriting Sort you won’t find such a solution.

Dim myList As New List<int>() { 8, 4, 6, 2, 1, 5, 3, 1, 7 }
Dim myRange = myList.GetRange(2,4)

myRange.Sort(yourComparer)
Dim i = 2;
For Each item in myRange
    mylist(i) = item
    i += 1
Next
Konrad Rudolph