如何替换集合中的元素

时间:2018-08-24 13:39:50

标签: c# .net collections

我想做的事情看起来很简单-我想在ICollection<T>中找到一个满足给定谓词的元素,然后用另一个替换。在C ++中,我会这样写:

for(auto &element : collection) {

    if(predicate(elem)) {
        element = newElement;
    }
}

通过引用获取元素并重新分配。但是在做

foreach(ref var element in collection)
C#中的

无法编译,而且我不确定如果编译后它甚至可以执行我想要的操作。如何访问集合中的物理参考进行修改?

我的方法签名是否有帮助:

public static void ReplaceReference<T>(
    ICollection<T> collection, 
    T newReference, 
    Func<T, bool> predicate)

编辑:

由于不清楚,我不能只拿ICollection<T>并将其更改为其他名称。我得到一个ICollection-这就是我所知道的,我无法更改。无论我多么希望自己成为IList,还是IEasilyReplacable我都无法影响它。

3 个答案:

答案 0 :(得分:2)

  • ICollection<T>在这种情况下不是最好的。 IList<T>允许您分配索引器。
  • 另一种选择是在您迭代时创建一个新集合。
  • 您还可以编写某种包装器,该包装器是集合中的实际引用并包含以下值:
ICollection<Wrapper<T>> collection = ...;

foreach(var wrapper in collection)
{
    wrapper.Value = newValue;
}

答案 1 :(得分:1)

据我了解,您想根据给定的谓词替换集合中的特定项目,我尝试了以下代码,对我来说很好用。

我创建了一个包含4个项目的字符串列表,我让我的通用方法搜索值为“名称1”的字符串是否正确,应该将其更改为值“名称5”。

我已经使用控制台应用程序对其进行了测试,因此您可以通过使用Console.WriteLine();创建显示列表值的forloop来对其进行测试。

    public void Main(string[] args)
    {
        List<string> list = new List<string>();
        list.Add("Name 1");
        list.Add("Name 2");
        list.Add("Name 3");
        list.Add("Name 4");

        Func<string, bool> logicFunc = (listItemValue) => listItemValue == "Name 1";
        ReplaceReference(list, "Name 5", logicFunc);
    }

    public static void ReplaceReference<T>(ICollection<T> collection, T newReference, Func<T, bool> predicate)
    {
        var typeName = typeof(T).Name;
        var newCollection = collection.ToList();
        for (int i = 0; i < newCollection.Count; i++)
        {
            if (predicate(newCollection[i]))
            {
                newCollection[i] = newReference;
            }
        }
    }

答案 2 :(得分:-1)

所以我把头撞在墙上,想出了一个非常简单的解决方案来解决特定的替换问题,即找到,删除然后添加。

var existing = collection.FirstOrDefault(predicate);

if (existing != null)
{
    collection.Remove(existing);    
    collection.Add(newReference);
}

但是,我认为这是解决我的foreach问题的一种变通方法,因此已将此问题发布为后续问题:Grab element from a Collection by reference in a foreach

编辑:

对于丹尼尔·A·怀特的评论:

仅处理第一个是我打算做的,但是可以轻松地将其更改为全部替换:

var existing = collection.Where(predicate);

foreach(var element in existing)
{
    collection.Remove(element);
}

for(int i = 0; i < existing.Count); ++i)
{
    collection.Add(newReference);
}

关于排序-ICollection不一定要排序。因此,解决该问题的方法将是创建一个通用性较低的新方法

static void ReplaceReference<T>(
    IList<T> list, 
    T newReference, 
    Func<T, bool> predicate)

将使用索引器替换值

for(int i = 0; i < list.Count; ++i)
{
    if(predicate(list[i]))
    {
        list[i] = newReference;
        // break here if replace-one variant.
    }
}

现在,在main方法中,我们检查集合是否为IList,因此是有序的,并将其传递给有序的版本:

if(collection is IList<T> list)
{
    ReplaceReference(list, newReference, predicate);
    return;
}

================================================ ==========================

旁注:当然也有dumbo方法:

var newCollection = new List<T>();

foreach(var element in collection)
{
    newList.Add(predicate(element) ? newReference : element);
}

collection.Clear();

foreach(var newElement in newCollection)
{
    collection.Add(newElement);
}

但是效率很低。