【问题标题】:Assign values from one list to another using LINQ使用 LINQ 将值从一个列表分配给另一个列表
【发布时间】:2012-03-14 18:50:57
【问题描述】:

您好,我在将属性值从一个列表项分配给另一个项时遇到了一点问题。我知道我可以通过迭代两个列表等来解决它“旧方法”,但我正在寻找使用 LINQ 的更优雅的解决方案。

让我们从代码开始...

class SourceType
{
    public int Id;
    public string Name;
    // other properties
}

class DestinationType
{
    public int Id;
    public string Name;
    // other properties
}

List<SourceType> sourceList = new List<SourceType>();
sourceList.Add(new SourceType { Id = 1, Name = "1111" });
sourceList.Add(new SourceType { Id = 2, Name = "2222" });
sourceList.Add(new SourceType { Id = 3, Name = "3333" });
sourceList.Add(new SourceType { Id = 5, Name = "5555" });

List<DestinationType> destinationList = new List<DestinationType>();
destinationList.Add(new DestinationType { Id = 1, Name = null });
destinationList.Add(new DestinationType { Id = 2, Name = null });
destinationList.Add(new DestinationType { Id = 3, Name = null });
destinationList.Add(new DestinationType { Id = 4, Name = null });

我想实现以下目标:

  • destinationList 应填写 sourceList 中相应条目的名称(按 Id)
  • destinationList 不应包含同时出现在两个列表中的条目(例如,应消除 ID:4,5) - 类似于内部连接
  • 我想避免使用更新的条目创建新的destinationList,因为这两个列表已经存在并且非常大, 所以没有“转换”或“选择新”。

最终destinationList应该包含:

1 "1111"
2 "2222"
3 "3333"

使用 LINQ 是否有某种优雅的(单行 Lambda?;)解决方案?

任何帮助将不胜感激!谢谢!

【问题讨论】:

  • LINQ 倾向于返回一个新的结果集,因为它遵循查询模式,因此它通常不用于更新它正在查询的序列。
  • 所以,澄清一下,您希望此过程将destinationList 更改为a) 从sourceList 中复制名称已经存在的位置,b) 删除destinationList 中没有sourceList 中的id 的任何项目?
  • 如果您的列表非常大并且您想使用 inne-join 语义,请考虑使用列表以外的其他内容。您需要按 Id 索引这两个列表,否则加入它们会非常慢
  • 搜索列表会很昂贵,并且算法的运行时间为 O(N^2)。对于第一个列表 (N) 中的每个项目,您必须在第二个列表中找到与 id 匹配的项目。 (N) 如果您打算针对多个项目执行此操作,我会考虑使用针对搜索进行优化的不同数据结构。
  • @JamesMichaelHare - 是的,或者反过来,首先以某种方式通过 Id 加入,然后分配名称。

标签: c# .net linq list lambda


【解决方案1】:

我会建立一个字典并使用它:

Dictionary<int, string> map = sourceList.ToDictionary(x => x.Id, x => x.Name);

foreach (var item in destinationList)
    if (map.ContainsKey(item.Id))
        item.Name = map[item.Id];

destinationList.RemoveAll(x=> x.Name == null);

【讨论】:

  • 嗯,是的,这看起来很有希望!你是对的,这里的性能很重要。似乎是我问题的最佳答案,我将进一步探索。谢谢!
  • 好的,就是这样。不完全是我想象的,但它工作得很好。谢谢!
【解决方案2】:

希望这会是您想要的结果。首先根据 key(Id) 加入两个列表,然后从 sourceList 中设置属性值。

        var result = destinationList.Join(sourceList, d => d.Id, s => s.Id, (d, s) =>
        {
            d.Name = s.Name;
            return d;
        }).ToList();

【讨论】:

  • 这拯救了我的一天!谢谢!!
【解决方案3】:

除非“避免创建新的destinationList”的最后一个要求,这应该可以工作

var newList = destinationList.Join(sourceList, d => d.Id, s => s.Id, (d, s) => s);

要注意“避免创建新的destinationList”,可以使用下面的方法,这与循环遍历整个列表没有任何不同,只是它可能不那么冗长。

destinationList.ForEach(d => {
                               var si = sourceList
                                           .Where(s => s.Id == d.Id)
                                           .FirstOrDefault();
                               d.Name = si != null ? si.Name : "";
                             });
destinationList.RemoveAll(d => string.IsNullOrEmpty(d.Name));

【讨论】:

  • 这是O(n^2) - 请改用字典进行查找
  • @BrokenGlass,你的意思是 O(n)。即使插入,字典查找也应该更快。理想情况下,这些列表可能应该以字典开头(假设 Id 是唯一的)。
  • @amit_g - 我尝试了加入,非常有趣,但我无法进一步分配相应的名称。第二个也很有趣……
  • “我无法进一步指定相应的名称。”是什么意思?第一个是选择其中已经有名称的源。请注意,如果列表很长,这些不是最有效的方法。如果您的列表很长,请使用@BrokenGlass 发布的答案或至少执行基准测试。
  • @amit_g: 我不是说 O(n) - 你的代码是 O(n^2) 因为你做了一个 Foreach = O(n) 和一个嵌套的 Where(..) 这是还有O(n) -> 所以它是O(n^2)
【解决方案4】:

坦率地说,这是最简单的:

var dictionary = sourceList.ToDictionary(x => x.Id, x => x.Name);
foreach(var item in desitnationList) {
    if(dictionary.ContainsKey(item.Id)) {
        item.Name = dictionary[item.Id];
    }
}
destinationList = destinationList.Where(x => x.Name != null).ToList();

你可以用 Join 做一些丑陋的事情,但我不会打扰。

【讨论】:

    【解决方案5】:

    我希望这对你有用。最后,destinationList 有正确的数据,没有创建任何类型的新列表。

            destinationList.ForEach(x =>
            {
                SourceType newSource = sourceList.Find(s=>s.Id == x.Id);
                if (newSource == null)
                {
                    destinationList.Remove(destinationList.Find(d => d.Id == x.Id));
                }
                else
                {
                    x.Name = newSource.Name;
                }
            });
    

    【讨论】:

      猜你喜欢
      • 2012-06-24
      • 1970-01-01
      • 1970-01-01
      • 2020-05-04
      • 2017-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-13
      相关资源
      最近更新 更多