C#如何从另一个列表更新列表

22

我有两个List<object>,第一个,我们称之为ListA,更像是完整的列表,而第二个ListB则是修改过的列表。现在我想用ListB修改ListA。这可行吗?如果可以,我该如何做呢?目前,这是我所拥有的代码,但它不起作用:

var ListB = _repository.Get(m => m.Approved == true).ToList();
foreach (var x in ListB)
{
  ListA.Where(d => d.Name == x.Name).First() = x;
}

return ListA;

编辑:视觉呈现以说明在我的情况下“修改”意味着什么

ListA
Id     Name      Age
1     John       14
2     Mark       15
3     Luke       13
4     Matthew    18

ListB
Id     Name      Age
2     Mark       0
4     Matthew    99

'修改'后,ListA应该看起来像:

ListA
Id     Name      Age
1     John       14
2     Mark       0
3     Luke       13
4     Matthew    99

3
在这种情况下,你需要定义“修改”一词的含义。 - Sami Kuhmonen
1
@SamiKuhmonen 谢谢,麻烦您看一下我的修改。 - super-user
@ArielB 谢谢你,但那是一个打字错误。它仍然不起作用。 - super-user
1
是的,我现在已经检查过了。你的问题在于当通过“First”返回一个列表项时,你得到的是它的引用,即使你改变了值,它也不会反映在列表中。 你必须去到列表中的特定位置并替换该值。 - ArielB
1
@Oliver他并没有修改他正在迭代的列表,他是使用LINQ从列表中获取特定项,更改它对列表没有任何影响(仅在更改值内部时才有影响)-我会编写一些“复制”代码来复制他所拥有的数据。 - ArielB
显示剩余2条评论
5个回答

24

据我理解,您希望只更新年龄。而且您不需要使用 Where().First(),您可以直接使用 First()

foreach (var x in ListB)
{
    var itemToChange = ListA.First(d => d.Name == x.Name).Age = x.Age;
}

如果您不确定在ListA中是否存在该项,则应使用FirstOrDefault()和if语句进行检查。

foreach (var x in ListB)
{
    var itemToChange = ListA.FirstOrDefault(d => d.Name == x.Name);
    if (itemToChange != null)
         itemToChange.Age = x.Age;
}

有没有一种方法可以同时更新所有属性,我的意思是如何像 itemToChange = x 这样更新它,这是不可能的吗? - super-user
@super-user,你必须实现复制或深度复制方法,就像其他人建议的那样。 - Valentin
@super-user 不建议这样做,因为如果你有一个类作为数据成员 - 你将会进行浅拷贝,这意味着两个不同的类将引用同一个对象。 - ArielB

5
你可以根据Id的值,从ListA中移除所有ListB的元素,然后将ListB添加到ListA中,并使用Id进行排序。
var newlist = ListA.Where(s => !ListB.Any(p => p.Id == s.Id)).ToList();
newlist.AddRange(ListB);
ListA = newlist.OrderBy(o => o.Id).ToList();

4

当使用Where和First返回IEnumerable时,您只能修改列表的节点,而不能重新分配。

选项0 - 通用方法

using System.Collections.Generic;

//...

   var itemToUpdate = ListA.FirstOrDefault(d => d.Name == x.Name);
   if (itemToUpdate != null) {
       ListA[ListA.IndexOf(itemToUpdate)] = x;
   }

选项1 - 实现更新方法或手动执行字段更新

ListA.First(d => d.Name == x.Name).Update(x);

我应该引用什么来使用IndexOf()或Update(),两者都对我无效。 - super-user
让我们假设你在列表中使用的类名为“Person”,前往“Person”类并添加一个“Copy(Person p)”方法。然后使用浅拷贝/深度拷贝到该对象即可完成。因为IEnumerable没有索引,所以没有IndexOf - 这是List方法(确保ListA确实是List),而更新是你必须编写的内容。 - ArielB
IndexOf方法适用于List<>类,而Update是一个方法,你应该实现它,或者其他用户编写-只需更改Age字段。如果你有10-20个字段,Update方法将非常方便。 - Andrey Ershov
如果没有找到任何项,它将抛出 "InvalidOperationException"。更安全的解决方案是使用 "FirstOrDefault" 并在进行任何进一步操作之前检查 null。 - Hypnobrew
@Merryweather 我甚至不打算使用字典来搜索元素 :) - Andrey Ershov

3

进一步阐述aershov的回答:

ListA.Where(d => d.Name == x.Name).First().CopyFrom(x);

然后在你的Person类中:

public class Person
{
   // ... Name, Id, Age properties...

   public void CopyFrom(Person p)
   {
      this.Name = p.Name;
      this.Id = p.Id;
      this.Age = p.Age;
   }
}

当然要检查null值和其他值。


0

你也可以使用带有 IEqualityComparer 的 Union 方法:

var newList = ListB.Union(ListA, new PersonEqualityComparer());

class PersonEqualityComparer : IEqualityComparer<Person>
{
    public bool Equals(Person person1, Person person2)
    {
        if (person1 == null && person2 == null)
            return true;
        else if ((person1 != null && person2 == null) ||
                (person1 == null && person2 != null))
            return false;

        return person1.Id.Equals(person2.Id);
    }

    public int GetHashCode(Person item)
    {
        return item.Id.GetHashCode();
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接