【问题标题】:Combining lists but getting unique members组合列表但获得唯一成员
【发布时间】:2010-04-09 01:29:08
【问题描述】:

我在组合列表时有一点特殊要求。我将尝试用一个例子来说明。假设我正在使用 2 个 GamePlayer 对象列表。 GamePlayer 有一个名为 LastGamePlayed 的属性。通过 GamePlayer.ID 属性标识唯一的 GamePlayer。现在我想将 listA 和 listB 合并到一个列表中,如果两个列表中都存在给定的玩家,我想保留 listA 中的值。

我不能只组合列表并使用比较器,因为我的唯一性基于 ID,如果我的比较器检查 ID,我将无法控制它是选择 listA 还是 listB 的元素。我需要类似的东西:

for each player in listB
{
    if not listA.Contains(player) 
    {
        listFinal.Add(player)
    }
}

但是,是否有更优化的方法来执行此操作,而不是为 listB 中的每个元素搜索 listA?

****EDIT****:或者,如果我想根据 LastGamePlayed 的值选择我保留的 GamePlayer(而不是知道 ListA 优先于 ListB)怎么办?所以我想要一个唯一的 GamePlayer 对象列表,但对于每个玩家,我想要具有最新 LastGamePlayed 的 GamePlayer 对象?基本上我需要一种方法来确定当有重复的 GamePlayers 时要保留哪个对象。

【问题讨论】:

  • listFinal 是否会包含所有 listA 以及 listB 中不存在于 listA 中的所有项目?

标签: .net linq list


【解决方案1】:

您应该能够使用 linq 可枚举扩展 Concat 和 Exept 来实现这一点。

listA.Concat(listB.Except(listA);

这将删除 B 中与 A 匹配的项目,并将结果添加到 A。

您必须编写一个按 ID 进行比较的 IEqualityComparer。

这些方法的文档可以在这里找到:

MSDN Enumerable Extensions

IEqualityComparer 文档可以在这里找到:

MSDN IEqualityComparer

【讨论】:

    【解决方案2】:

    现在已经澄清了,问题基本上是这样的:

    • 合并列表 A 和列表 B 中的所有元素,如果有任何重复,请保留最新的 LastGamePlayed

    我会通过分组来做到这一点:

    var players = from p in listA.Concat(listB)
                  group p by p.ID into g
                  select g.OrderByDescending(x => x.LastGamePlayed).First();
    

    如果性能是一个问题,有“更快”的方法来写这个,但我会从这个开始。

    【讨论】:

      【解决方案3】:

      您可以编写一个 O(n log n) 解决方案,方法是从 list2 构建一个集合,然后用 list1 覆盖(或插入)项目,然后将该集合转换回一个列表。

      如果列表已经排序,您可以通过手动合并来完成 O(n)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-01-18
        • 2023-03-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-07-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多