sahil sahil - 3 days ago 5
C# Question

c# list move 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));


numberToBeMovedOnTop is a variable.

This gives me the desired result but the problem is can i have 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 inbuilt c# function without iterating twice in the list?

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