Ivan-Mark Debono
Ivan-Mark Debono

Reputation: 16290

How to replace an item in an IEnumerable<T>?

Currently, to replace an item I'm using the following code:

var oldItem = myList.Single(x => x.Id == newItem.Id);
var pos = myList.ToList().IndexOf(oldItem);

myList.Remove(oldItem);

myList.ToList().Insert(pos, newItem);

So, I created an extension to do the same as above but using lambda expression, and I came up with this:

public static ICollection<T> Replace<T>(this IEnumerable<T> list, T oldValue, T newValue) where T : class
{
    if (list == null)
        throw new ArgumentNullException(nameof(list));

    return list.Select(x => list.ToList().IndexOf(oldValue) != -1 ? newValue : x).ToList();
}

So I can use it as follows:

var oldItem = myList.Single(x => x.Id == newItem.Id);
myList = myList.Replace(oldItem, newItem);

However, it's not working. What am I missing?

Upvotes: 1

Views: 3894

Answers (2)

casperOne
casperOne

Reputation: 74530

While you can't replace the item in the materialized collection itself, you can replace the item that is yielded from a different IEnumerable<T> at a certain position.

All you have to do is use the Select extension method on IEnumerable<T> to map to the new item when the Id property matches, and use the new IEnumerable<T> instance, like so:

// Assuming newItem is already defined, has the value you want to yield
// and T is the type of newItem
IEnumerable<T> newEnumerable = myList.Select(i => 
    i.Id == newItem.Id ? newItem : i
);

Then, when you iterate through the newEnumerable, when the item in the old list has an Id equal to newItem.Id, it will yield newItem.

Upvotes: 7

Sherlock
Sherlock

Reputation: 1030

IEnumerable is for traversing a generic data structure. Think about it as read-only access. In fact, making modifications to the IEnumerable while enumerating it is a big NO NO. Your original solution is fine, except for the last line. Just do Remove and Insert.

Upvotes: 0

Related Questions