在两个很大的列表中找出不同之处



我有两个列表,每个列表大约有1k人。我想做的是找出两者之间剩下的人。

$BunchoEmail = Import-Csv C:tempDirectory.csv | Select-Object primaryEmail -ExpandProperty primaryEmail
$GoogleUsers = gam print users fields suspended | ConvertFrom-Csv | Where-Object suspended -ne $true | Select-Object primaryEmail -ExpandProperty primaryEmail
$objects = @{
ReferenceObject  = $GoogleUsers
DifferenceObject = $BunchoEmail
}
Compare-Object @objects

上面没有产生我想要的东西。

找到不同之处的最佳方法是什么?

Compare-Object能够找到一个集合中相对于另一个集合缺少的元素,反之亦然,或者两者都缺少。

然而,它可能是,并且考虑到您提到列表,听起来您正在寻找一个性能良好的解决方案。

  • 然而,具有1000个项目的集合在实践中可能不是问题

  • 因此,以下内容可能足以获得$BunchoEmail中不在$GoogleUsers中的所有条目(用=>代替<=以反转逻辑(:

    (Compare-Object -PassThru $BunchoEmail $GoogleUsers).
    Where({ $_.SideIndicator -eq '<=' })
    
  • 获取不在两个集合中的条目(对于任一的集合都是唯一的(更容易:

    Compare-Object -PassThru $BunchoEmail $GoogleUsers
    

至于提高性能

将类型[System.Collections.Generic.HashSet`1]与LINQ相结合可以实现快速简洁的解决方案:

注:

  • HashSet的使用意味着结果的报告没有特定的顺序;要按排序,请改用[System.Collections.Generic.SortedSet[string]]。(从.NET 6开始,没有用于维护插入顺序的内置类型(。

  • 下面的解决方案是真正的集合操作,即它们报告不同的差异,而不是Compare-Object。例如,如果唯一的电子邮件foo@example.org在集合中出现两次,则下面的解决方案只报告一次

  • Compare-Object不同,默认情况下,HashSetSortedSet类型区分大小写;您可以使用System.StringComparer将相等比较器传递给不区分大小写的行为的构造函数;例如:

    [System.Collections.Generic.HashSet[string]]::new(
    [string[]] ('foo', 'FOO'),
    [System.StringComparer]::InvariantCultureIgnoreCase
    )
    

要获取$BunchoEmail中不在$GoogleUsers中的所有条目,请使用[System.Linq.Enumerable]::Except()(反转逆解的操作数(:

[Linq.Enumerable]::Except(
[System.Collections.Generic.HashSet[string]] $BunchoEmail,
[System.Collections.Generic.HashSet[string]] $GoogleUsers
)

注意:您也可以使用哈希集的.ExceptWith()方法,但这需要将其中一个哈希集存储在辅助变量中,然后在适当的位置更新,类似于下面的.SymmetricExceptWith()解决方案

使用哈希集的.SymmetricExceptWith()方法:,获取不在两个集合中的条目(对于任一的集合都是唯一的,在集合术语中称为对称差(需要付出更多的努力

# Load one of the collections into an auxiliary hash set.
$auxHashSet = [System.Collections.Generic.HashSet[string]] $BunchoEmail
# Determine the symmetric difference between the two sets, which
# updates the calling set in place.
$auxHashSet.SymmetricExceptWith(
[System.Collections.Generic.HashSet[string]] $GoogleUsers
)
# Output the result
$auxHashSet

将每个列表加载到[hashtable]:中

$emailTable = @{}
$BunchoEmail |ForEach-Object { $emailTable[$_] = $_ }
$gsuiteTable = @{}
$GoogleUsers |ForEach-Object { $gsuiteTable[$_] = $_ }

现在,您可以迭代一个列表,并使用Where-Object:检查另一个列表是否不包含任何特定的电子邮件地址

$notInGSuite = $BunchoEmail |Where-Object { -not $gsuiteTable.ContainsKey($_) }
$notInEmailList = $GoogleUsers |Where-Object { -not $emailTable.ContainsKey($_) }

ContainsKey()在哈希表上的时间复杂度为O(1(,因此它将继续适用于包含1000封电子邮件的列表

最新更新