sahil sahil - 2 days ago 3
C# Question

Move list elements meeting condition to the top of the list

I want to move specific number to the top of this list.

int numberToBeMovedOnTop = 4;
List<int> lst = new List<int>(){1, 2, 3, 4, 5, 5, 4, 7, 9, 4, 2, 1};
List<int> lstOdd = lst.FindAll(l => l == numberToBeMovedOnTop);
lstOdd.AddRange(lst.FindAll(l => l != numberToBeMovedOnTop));


Where
numberToBeMovedOnTop
is a variable.

This gives me the desired result but is a better solution for this? I can iterate the list once and swap first occurence of
numberToBeMovedOnTop
with first element, second occurence with
numberToBeMovedOnTop
with second element and so on. But can this be done with some built-in C# function without iterating the list twice?

Answer

You could use LINQ:

List<int> lstOdd = lst.OrderByDescending(i => i == numberToBeMovedOnTop).ToList();

Why OrderByDescending? Because the comparison returns a bool and true is higher than false. You could also use:

List<int> lstOdd = lst.OrderBy(i => i == numberToBeMovedOnTop ? 0 : 1).ToList();

Note that this works because OrderBy and OrderByDescending are performing a stable sort. That means that the original order remains for all equal items.


For what it's worth, here is an extension method that works with any type and predicate and is a little bit more efficient:

public static List<T> PrependAll<T>(this List<T> list, Func<T, bool> predicate)
{
    var returnList = new List<T>();
    var listNonMatch = new List<T>();
    foreach (T item in list)
    {
        if (predicate(item))
            returnList.Add(item);
        else
            listNonMatch.Add(item);
    }
    returnList.AddRange(listNonMatch);
    return returnList;
}

Usage: List<int> lstOdd = lst.PrependAll(i => i == numberToBeMovedOnTop);

Comments