【问题标题】:LINQ merging 2 lists, keeping seqeunce and origin [duplicate]LINQ合并2个列表,保持顺序和来源[重复]
【发布时间】:2019-06-08 01:57:50
【问题描述】:

这里我有 2 个相同对象类型的列表。

object = {id: xxx, ...} // attribute "id" is used to find the identical obj

List oldSet = [old1, old2, old3];
List newSet = [new2, new3, new4];

// old2 = {id= 2, result = 5, ...}
// new2 = {id= 2, result = 1, ...}
// expected result = {oldSet: old2; newSet: new2}

我想合并两个列表,同时保留它来自哪个列表的来源。

预期结果如下:

List mergedSet = [{old1, null}, {old2, new2}, {old3, new3}, {null, new4}];

我正在考虑使用 LINQ C#,但卡在某个地方。

请多多指教。

谢谢! :)

【问题讨论】:

  • 听说过字典吗?还是多维数组?
  • mergedSetType 是什么?是List<Tuple<Item, Item>>吗?
  • 我认为结果类型可以是可选的。只要我能分辨出这个项目来自 oldSet 或 newSet,并将具有相同 id 的项目组合起来。谢谢你的提示
  • 如果您能提供minimal reproducible example,那就太好了。您的代码按原样无法编译。
  • 您的问题中缺少以下详细信息以提供有用的答案:(1)oldSetnewSet 将具有相同顺序的项目,即如果项目的id在同一个索引中不匹配是否可以安全地假设该项目不存在于另一个列表中? (2)应该保持谁的顺序?即,如果两个列表的所有内容都不同,并且任何项目都没有单一匹配项,那么输出应该是什么?

标签: c# list linq merge


【解决方案1】:

这里有一些代码可以用 Linq 做你想做的事。它基本上遍历所有旧列表,并通过从新列表中查找匹配项将对添加到合并列表中(如果未找到匹配项,则添加 null 作为第二项)。然后它遍历新列表中的剩余项目,并将它们与null 添加为第一个项目。它选择具有两个属性的动态类型:OldSetNewSet,因此您知道每个项目的来源。

合并代码很简单:

var mergedSet = oldSet.Select(o =>
    new {OldSet = o, NewSet = newSet.FirstOrDefault(n => n.id == o.id)})
    .Concat(newSet.Where(n => oldSet.All(o => o.id != n.id)).Select(n =>
        new {OldSet = (Item) null, NewSet = n}));

这基于以下项目类别:

class Item
{
    public int id { get; set; }
    public string result { get; set; }
    public override string ToString()
    {
        return $"{result}{id}";
    }
}

我们创建我们的列表:

List<Item> oldSet = new List<Item>
{
    new Item {id = 1, result = "old"},
    new Item {id = 2, result = "old"},
    new Item {id = 3, result = "old"},
};

List<Item> newSet = new List<Item>
{
    new Item {id = 2, result = "new"},
    new Item {id = 3, result = "new"},
    new Item {id = 4, result = "new"},
};

运行合并代码(首先是sn-p),然后显示结果:

foreach (var item in mergedSet)
{
    Console.WriteLine($"{item.NewSet},{item.OldSet}");
}

输出

【讨论】:

  • 这个任务的代码太多了.... Linq 专门用来做这种事情。在这里使用元组没有意义,几个连接或联合就可以了。
  • 你是对的,我更正了我的代码,删除了不相关的 cmets... :)
  • @DrunkenCodeMonkey 酷。我还纠正了我的错误,将合并代码从 2 行减少到 1 行(并且还使用了动态类型),以防有人投反对票。
【解决方案2】:

试试这样的:

            List<string> oldSet = new List<string>() {"old1", "old2", "old3"};
            List<string> newSet = new List<string>() {"new2", "new3", "new4"};

            var results = oldSet.Select((x,i) => new { oldSet = x, newSet = newSet[i]}).ToList();

【讨论】:

  • 这个问题有点破,但似乎他不只是压缩它们,而是根据数据中的数字进行配对。
【解决方案3】:

您可以离开加入这两个列表。我编辑了答案,因为您实际上需要左加入两次,联合,并应用选择不同来获得 oldSet = null 且没有重复的情况...

    var mergedSet = (from o in oldSet
                     join n in newSet on o.id equals n.id into ns
                     from n in ns.DefaultIfEmpty()
                     select new { OldSet = o, NewSet = n })
                    .Union(from n in newSet
                           join o in oldSet on n.id equals o.id into os
                           from o in os.DefaultIfEmpty()
                           select new { OldSet = o, NewSet = n })
                    .Distinct();

【讨论】:

    【解决方案4】:

    可能有点矫枉过正,但如果你真的想使用 LINQ

    List<Item> oldSet = new List<Item>
    {
        new Item {id = 1, result = "old"},
        new Item {id = 2, result = "old"},
        new Item {id = 3, result = "old"},
    };
    
    List<Item> newSet = new List<Item>
    {
        new Item {id = 2, result = "new"},
        new Item {id = 3, result = "new"},
        new Item {id = 4, result = "new"},
    };
    
    var resultL = oldSet.GroupJoin(
              newSet, 
              o => o.id,
              n => n.id,
              (o,n) => new { Old = o, New = n })
        .SelectMany(
              n => n.New.DefaultIfEmpty(),
              (o,n) => new Tuple<Item,Item>(o.Old,n));
    
    
     var resultR= newSet.GroupJoin(
              oldSet, 
              n => n.id,
              o=> o.id,
              (n,o) => new { Old = o, New = n })
        .SelectMany(
              o=> o.Old.DefaultIfEmpty(),
              (n,o) => new Tuple<Item,Item>(o,n.New));
    
    var result = resultL.Union(resultR).Distinct();
    

    【讨论】:

      【解决方案5】:

      在这种情况下,您必须使用两个GroupJoinUnion 的结果。 看下面的代码:

      var res1 = oldSet.GroupJoin(newSet, o => o, k => k, (x, y) => { var yy = y.FirstOrDefault(); return new { X = x, Y = yy }; });
      var res2 = newSet.GroupJoin(oldSet, o => o, k => k, (x, y) => { var yy = y.FirstOrDefault(); return new { X = yy, Y = x }; });
      var result = res1.Union(res2).ToList();// Your result is here
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-07-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-02
        相关资源
        最近更新 更多