score:11

Accepted answer

If you're looking to conditionally project a Foo to another Foo (leaving others untouched), you can do something like:

IEnumerable<Foo> foos = ...

var transformed = foos.Select(foo => myCondition(foo) ? transform(foo) : foo);

On the other hand, if you only want to project Foos that match the condition:

var transformed = foos.Where(foo => myCondition(foo))
                      .Select(foo => transform(foo));

Do note that both of these return new sequences - LINQ isn't normally used to modify existing collections. You could of course materialize the results into a collection, overwriting an existing variable if necessary.

// assuming the transform is from Foo -> Foo
foos = foos.Select(foo => transform(foo)).ToList();

Since you specifically mention lists, there is another non-LINQ immediate-execution alternative to the first query - the List<T>.ConvertAll method:

List<Foo> foos = ...

// implicitly List<Foo> assuming the transform is from Foo -> Foo
var transformed = foos.ConvertAll
                  (foo => myCondition(foo) ? transform(foo) : foo);

EDIT: Sounds like you're looking for a "ReplaceWhere" method - as far as I know, there is no direct framework method that replaces the elements of a list based on a predicate. It's easy to write one yourself though:

/// <summary>
/// Replaces items in a list that match the specified predicate,
/// based on the specified selector. 
/// </summary>
public static void ReplaceWhere<T>(this IList<T> list,
                                   Func<T, bool> predicate,
                                   Func<T, T> selector)
{
    // null-checks here.

    for (int i = 0; i < list.Count; i++)
    {
        T item = list[i];

        if (predicate(item))
            list[i] = selector(item);
    }
}

Usage:

List<int> myList = ...
myList.ReplaceWhere(i => i > 0, i => i * i);

score:4

You could certainly write a transformation function:

// allows you to transform every element
public static List<T> TransformAll<T>(this List<T> list,
                                      Func<T, T> converter)
{
    for (int i = 0; i < list.Count; i++)
    {
        list[i] = converter(list[i]);
    }
    return list;
}

// allows you to transform every element based on its index
public static List<T> TransformAll<T>(this List<T> list,
                                      Func<T, int, T> converter)
{
    for (int i = 0; i < list.Count; i++)
    {
        list[i] = converter(list[i], i);
    }
    return list;
}

// allows you to transform chosen elements
public static List<T> TransformWhere<T>(this List<T> list,
                                        Func<T, bool> predicate,
                                        Func<T, T> converter)
{
    for (int i = 0; i < list.Count; i++)
    {
        T item = list[i];
        if (predicate(item))
            list[i] = converter(item);
    }
    return list;
}

// allows you to transform chosen elements based on its index
public static List<T> TransformWhere<T>(this List<T> list,
                                        Func<T, int, bool> predicate,
                                        Func<T, int, T> converter)
{
    for (int i = 0; i < list.Count; i++)
    {
        T item = list[i];
        if (predicate(item, i))
            list[i] = converter(item, i);
    }
    return list;
}

Note that I made all my functions return the passed-in list so that you can use them fluently, like list.TransformAll(x => x + 2).Sum().


Related Articles