我有两个列表,每个列表大约有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
不同,默认情况下,HashSet
和SortedSet
类型区分大小写;您可以使用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封电子邮件的列表