1

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

$BunchoEmail = Import-Csv C:\temp\Directory.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

上面没有产生我想要的。

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

4

2 回答 2

5

Compare-Object能够找到一个集合相对于另一个集合缺少哪些元素,反之亦然,或两者兼而有之。

但是,它可能很,并且鉴于您提到了大型列表,听起来您正在寻找一个性能良好的解决方案。

  • 但是,包含 1,000 个项目的集合在实践中可能不是问题

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

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

    Compare-Object -PassThru $BunchoEmail $GoogleUsers
    

至于提高性能

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

笔记:

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

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

  • 与 不同Compare-ObjectHashSetandSortedSet类型默认区分大小写;您可以将相等比较器传递给构造函数以实现不区分大小写的行为,使用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
于 2021-07-22T20:37:23.277 回答
2

将每个列表加载到[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 封电子邮件的列表工作

于 2021-07-22T19:36:10.043 回答