【问题标题】:Comparing and merging a list of objects比较和合并对象列表
【发布时间】:2015-04-02 10:05:32
【问题描述】:

我有一个包含许多具有此定义的对象的列表:

Public Class Helper
    Public Property UserPrincipal As UserPrincipal
    Public Property Groups As New List(Of String)
    Public Property Server As New List(Of String)
End Class

假设,一个对象如下所示:

UserPrincipal.Name = Jan
Groups = {group_1, group_2, group_3}
Server = {Server1}

还有一个:

UserPrincipal.Name = Jan
Groups = {group_1, group_3}
Server = {Server2}

现在我想检查每个对象的属性“组”,如果一个对象的“组”包含另一个对象的“组”,则创建一个新对象。

所以新的对象列表应该如下所示:

UserPrincipal.Name = Jan
Groups = {group_1, group_2, group_3}
Server = {Server1, Server2}

这可以使用 linq 吗?

感谢和问候, 一月

更新:10:42:将“服务器”属性的类型从字符串更改为列表(字符串)

12:04 更新:让我试着澄清一下我的问题。 任务是收集服务器本地组的成员。为此,我使用具有正确凭据的新主体上下文连接到每个服务器,获取正确的组(它是远程桌面用户组)并获取该组的所有成员。 使用此信息,我填充了提到的“帮助器”对象,其中包含用户主体(它是组的成员)、组(是远程桌面用户组的成员)和服务器名称。

所以我得到了 n * Helper-objects,其中 n 是服务器计数。

现在,有两个要求:假设我在这里有两台服务器,server1server2。一切都相等,但服务器名称不同,所以我只想要一个属性为 Server = {server1, server2} 的对象。

第二个要求与第一个基本相同,但是:如果Groups 属性包含添加至少一个唯一相关性并将该组添加到列表中(如果它尚未在列表中),请执行此操作。

不知道现在是否更清楚:) 现在将显示一个简短的示例。

对象 1:
UserPrincipal.Name = 一月
组 = {域用户}
服务器 = {Server1}

对象 2:
UserPrincipal.Name = 一月
组 = {域用户}
服务器 = {Server2}

预期对象:
UserPrincipal.Name = 一月
组 = {域用户}
服务器 = {服务器 1,服务器 2}

示例 2:
对象 1:
UserPrincipal.Name = 一月
组 = {域用户、测试用户}
服务器 = {Server1}

对象 2:
UserPrincipal.Name = 一月
组 = {测试用户}
服务器 = {Server2}

预期对象:
UserPrincipal.Name = 一月
组 = {域用户、测试用户}
服务器 = {服务器 1,服务器 2}

最后一个,噗:

对象 1:
UserPrincpial.Name = 一月
组 = {测试用户}
服务器 = {Server1}

对象 2:
UserPrincipal.Name = 一月
组 = {域用户}
Server = {Server1} 或 {Server2} 等无关紧要。

预期结果:没有变化导致属性groups 完全不同。

【问题讨论】:

  • 您不能将属性Server 的类型从字符串更改为List(Of string)。因此,您要么必须首先使用列表,要么使用字符串并用逗号(或不同的分隔符)连接所有内容。
  • 可以,只是不允许使用 Option Strict On。但请注意,不建议这样做
  • UserPrincipal 是如何关联的,同一个组是否也有相同的UserPrincipal?或者你想保留哪一组,第一个?
  • “UserPrincipal”与组没有直接关系,但它通常是组的成员。但由于我在这里没有使用“GroupPrincipal”的列表,所以没关系。
  • 在您的示例数据中,GroupsServer 属性似乎只是为每个 UserPrincipal 合并。但你的描述听起来像是某种交集。你能澄清一下吗?

标签: vb.net linq


【解决方案1】:

根据您更新的问题和您的 cmets,这似乎是您想要的:

Dim upGroups = From helper In helpers 
               Group helper By helper.UserPrincipal Into Group
               Select New Helper With {
                 .UserPrincipal = UserPrincipal,
                 .Groups = Group.SelectMany(Function(h) h.Groups).Distinct().ToList(),
                 .Server = Group.SelectMany(Function(h) h.Server).Distinct().ToList()
               }
Dim newHelpers = upGroups.ToList()

旧答案

您可以使用Groups.Intersect(h.Groups).Any() 检查哪些助手包含相交组。然后你可以使用循环来合并它们:

Dim query = From helper In helpers
            Let group = helpers.Where(Function(h) helper.Groups.Intersect(h.Groups).Any())

Dim processed As New HashSet(Of Helper)()
Dim newHelpers As New List(Of Helper)
For Each x In query
    If x.group.Any(AddressOf processed.Contains) Then
        ' was already processed, skip '
        Continue For
    End If
    Dim mergedHelper = New Helper With {
               .UserPrincipal = x.group.First().UserPrincipal,
               .Groups = x.group.SelectMany(Function(h) h.Groups).Distinct().ToList(),
               .Server = x.group.SelectMany(Function(h) h.Server).Distinct().ToList()
           }
    newHelpers.Add(mergedHelper)
    For Each helperInGroup In x.group
        processed.Add(helperInGroup)
    Next
Next

【讨论】:

  • 某处似乎有错误。它只吐出大约 5 个条目,而我的初始帮助列表包含近 20.000 个条目。 :)
  • @Jan:那为什么不正确呢?您的要求是合并所有具有相交组的助手,不是吗? 编辑等等,我看到你已经编辑了问题。
  • 我越来越接近你的方法了。我只是不使用您处理过的哈希集。但是,现在我为每台服务器获得了相同的结果集,而不仅仅是一个。使用您的代码,我只能获得一个用户主体,而不是全部。
  • @Jan:如果您不使用 HashSet,即使它们已经与其他助手合并,您也会添加原始助手。
  • 没错,但我如何只获得合并的?如果我使用你的代码,我所有的用户主体都消失了:)
猜你喜欢
  • 1970-01-01
  • 2015-01-05
  • 2021-06-24
  • 1970-01-01
  • 1970-01-01
  • 2022-06-26
  • 2019-01-03
  • 2020-03-05
  • 2013-08-19
相关资源
最近更新 更多