PowerShell:比较 2 个大型 CSV 文件以查找其中一个文件中不存在的用户
PowerShell: compare 2 large CSV files to find users that don't exist in one of them
我有 2 个 csv 文件,每个文件大约有 10,000 个用户。我需要计算有多少用户出现在 csv1 而不是 csv2 中。目前我有下面的代码。但是我知道这可能非常低效,因为它可能会循环多达 10,000 个用户 10,000 次。该代码永远需要 运行,我相信一定有更有效的方法。感谢任何帮助或建议我对 Powershell 还很陌生
foreach ($csv1User in $csv1) {
$found = $false
foreach ($csv2User in $csv2) {
if ($csv1User.identifier -eq $csv2User.identifier)
{
$found = $true
break
}
}
if ($found -ne $true){
$count++
}
}
如果您只是在寻找计数,那么这应该快得多。
$csv2 = Import-Csv $csvfile2
Import-Csv $csvfile1 |
Where-Object identifier -in $csv2.identifier |
Measure-Object | Select-Object -ExpandProperty Count
这是一个小例子
$csvfile1 = New-TemporaryFile
$csvfile2 = New-TemporaryFile
@'
identifier
bob
sally
john
sue
'@ | Set-Content $csvfile1 -Encoding UTF8
@'
identifier
bill
sally
john
stan
'@ | Set-Content $csvfile2 -Encoding UTF8
$csv2 = Import-Csv $csvfile2
Import-Csv $csvfile1 |
Where-Object identifier -in $csv2.identifier |
Measure-Object | Select-Object -ExpandProperty Count
输出很简单
2
如果您用 2 个 HashSet 替换嵌套循环,您将有两种计算两者之间异常的方法:
使用SymmetricExceptWith()
HashSet<T>.SymmetricExceptWith()
函数允许我们计算存在于任一集合中但不存在于两者中的术语子集:
# Create hashset from one list
$userIDs = [System.Collections.Generic.HashSet[string]]::new([string[]]$csv1.identifier)
# Pass the other list to `SymmetricExceptWith`
$userIDs.SymmetricExceptWith([string[]]$csv2.identifier)
# Now we have an efficient filter!
$relevantRecords = @($csv1;$csv2) |Where-Object { $userIDs.Contains($_.identifier) } |Sort-Object -Unique identifier
使用集合跟踪重复项
同样,我们可以使用哈希集来跟踪哪些术语至少被观察到一次,哪些被观察到不止一次:
# Create sets for tracking
$seenOnce = [System.Collections.Generic.HashSet[string]]::new()
$seenTwice = [System.Collections.Generic.HashSet[string]]::new()
# Loop through whole superset of records
foreach($record in @($csv1;$csv2)){
# Always attempt to add to the $seenOnce set
if(!$seenOnce.Add($record.identifier)){
# We've already seen this identifier once, add it to $seenTwice
[void]$seenTwice.Add($record.identifier)
}
}
# Just like the previous example, we now have an efficient filter!
$relevantRecords = @($csv1;$csv2) |Where-Object { $seenOnce.Contains($_.identifier) -and -not $seenTwice.Contains($_.identifier) } |Sort-Object -Unique identifier
使用哈希 table 作为分组结构
您还可以使用字典类型(例如 [hashtable]
)根据标识符对来自两个 csv 文件的记录进行分组,然后过滤每个字典条目中记录值的数量:
# Groups records on their identifier value
$groupsById = @{}
foreach($record in @($csv1;$csv2)){
if(-not $groupsById.ContainsKey($record.identifier)){
$groupsById[$record.identifier] = @()
}
$groupsById[$record.identifier] += $record
}
# Filter based on number of records with a distinct identifier
$relevantRecords = $groupsById.GetEnumerator() |Where-Object { $_.Value.Count -eq 1 } |Select-Object -Expand Value
我有 2 个 csv 文件,每个文件大约有 10,000 个用户。我需要计算有多少用户出现在 csv1 而不是 csv2 中。目前我有下面的代码。但是我知道这可能非常低效,因为它可能会循环多达 10,000 个用户 10,000 次。该代码永远需要 运行,我相信一定有更有效的方法。感谢任何帮助或建议我对 Powershell 还很陌生
foreach ($csv1User in $csv1) {
$found = $false
foreach ($csv2User in $csv2) {
if ($csv1User.identifier -eq $csv2User.identifier)
{
$found = $true
break
}
}
if ($found -ne $true){
$count++
}
}
如果您只是在寻找计数,那么这应该快得多。
$csv2 = Import-Csv $csvfile2
Import-Csv $csvfile1 |
Where-Object identifier -in $csv2.identifier |
Measure-Object | Select-Object -ExpandProperty Count
这是一个小例子
$csvfile1 = New-TemporaryFile
$csvfile2 = New-TemporaryFile
@'
identifier
bob
sally
john
sue
'@ | Set-Content $csvfile1 -Encoding UTF8
@'
identifier
bill
sally
john
stan
'@ | Set-Content $csvfile2 -Encoding UTF8
$csv2 = Import-Csv $csvfile2
Import-Csv $csvfile1 |
Where-Object identifier -in $csv2.identifier |
Measure-Object | Select-Object -ExpandProperty Count
输出很简单
2
如果您用 2 个 HashSet 替换嵌套循环,您将有两种计算两者之间异常的方法:
使用SymmetricExceptWith()
HashSet<T>.SymmetricExceptWith()
函数允许我们计算存在于任一集合中但不存在于两者中的术语子集:
# Create hashset from one list
$userIDs = [System.Collections.Generic.HashSet[string]]::new([string[]]$csv1.identifier)
# Pass the other list to `SymmetricExceptWith`
$userIDs.SymmetricExceptWith([string[]]$csv2.identifier)
# Now we have an efficient filter!
$relevantRecords = @($csv1;$csv2) |Where-Object { $userIDs.Contains($_.identifier) } |Sort-Object -Unique identifier
使用集合跟踪重复项
同样,我们可以使用哈希集来跟踪哪些术语至少被观察到一次,哪些被观察到不止一次:
# Create sets for tracking
$seenOnce = [System.Collections.Generic.HashSet[string]]::new()
$seenTwice = [System.Collections.Generic.HashSet[string]]::new()
# Loop through whole superset of records
foreach($record in @($csv1;$csv2)){
# Always attempt to add to the $seenOnce set
if(!$seenOnce.Add($record.identifier)){
# We've already seen this identifier once, add it to $seenTwice
[void]$seenTwice.Add($record.identifier)
}
}
# Just like the previous example, we now have an efficient filter!
$relevantRecords = @($csv1;$csv2) |Where-Object { $seenOnce.Contains($_.identifier) -and -not $seenTwice.Contains($_.identifier) } |Sort-Object -Unique identifier
使用哈希 table 作为分组结构
您还可以使用字典类型(例如 [hashtable]
)根据标识符对来自两个 csv 文件的记录进行分组,然后过滤每个字典条目中记录值的数量:
# Groups records on their identifier value
$groupsById = @{}
foreach($record in @($csv1;$csv2)){
if(-not $groupsById.ContainsKey($record.identifier)){
$groupsById[$record.identifier] = @()
}
$groupsById[$record.identifier] += $record
}
# Filter based on number of records with a distinct identifier
$relevantRecords = $groupsById.GetEnumerator() |Where-Object { $_.Value.Count -eq 1 } |Select-Object -Expand Value