我使用此代码匹配两个CSV文件并获取我需要的列
在此代码中,我比较了数据Matricule
name
和Firstname
,当我得到匹配时,我可以检索列' IGG'
但它很慢......(18行20分钟)
有人可以帮我这个吗?
这是我的代码:
foreach ($item in $fileContentIMM)
{
try
{
$Matricule = $item.'Matricule'
$name = $item.'Nom'
$firstname = $item.'Prenom'
# find first matching row in $$fileContentMagic using wildcard
$objMatch = $fileContentMagic | where { $_.'Matricule' -eq $Matricule -and $_.'NOM' -eq $name -and $_.'PRENOM' -eq $firstname}
##### check if any match found
if ($objMatch -eq $null)
{
$item | ForEach-Object {
$filechecktrue += [pscustomobject]@{
'MATRICULE' = $item.'Matricule'
'IGG' = 'noSet'
'NAME' = $item.'Nom'
'FIRSTNAME' = $item.'Prenom'
'SERVICE' = $item.'Service'
'Immeuble'= $item.'Immeuble'
'Niveau' = $item.'Niveau'
'Loc.' = $item.'Loc.'
'PDT' = $item.'PDT'
'Occ.' = $item.'Occ.'
'Site' = $item.'Site'
}
}
}
else
{
$item | ForEach-Object {
$filechecktrue += [pscustomobject]@{
'MATRICULE' = $item.'Matricule'
'IGG' = ($objMatch.'IGG' -join '/')
'NAME' = $item.'Nom'
'FIRSTNAME' = $item.'Prenom'
'SERVICE' = $item.'Service'
'Immeuble'= $item.'Immeuble'
'Niveau' = $item.'Niveau'
'Loc.' = $item.'Loc.'
'PDT' = $item.'PDT'
'Occ.' = $item.'Occ.'
'Site' = $item.'Site'
}
}
}
}
catch
{
"ERROR: Problem reading line - skipping :" | Out-File $LogFile -Append -Force
$item.nom + $item.prenom + $item.service| Out-File $LogFile -Append -Force
}
}
答案 0 :(得分:2)
我会读取您用于查找的文件,然后为此创建一个HashTable。 HashTables非常有效地进行查找。
尝试这样的事情,假设您在FileContentMagic
中没有任何重复项:
# Use any character here which is guaranteed not to be present in the Matricule, Nom,
# or Prenom fields
$Delimiter = '|'
# Read the FileContent Magic into a HashTable for fast lookups
# The key is Matricule|Nom|Prenom
# The value is IGG joined with a forward slash
$FileContentMagic = @{}
Import-Csv -Path $FileContentMagicFileName | ForEach-Object {
# Here we build our lookup key. The Trim() is just in case there's any leading or trailing
# whitespace You can leave it out if you know you don't need it
$Key = $_.Matricule.Trim(), $_.Nom.Trim(), $_.Prenom.Trim() -join $Delimiter
# Since we only need the IGG value joined with a /, we'll just keep that
$Value = $_.IGG -join '/'
$FileContentMagic.Add($Key, $Value)
}
$FileContentIMM = Import-Csv -Path $FileContentIMMFileName
$FileCheckTrue = foreach ($item in $FileContentIMM) {
$Key = $_.Matricule.Trim(), $_.Nom.Trim(), $_.Prenom.Trim() -join $Delimiter
[PSCustomObject]@{
'MATRICULE' = $item.'Matricule'
'IGG' = if ($FileContentMagic.ContainsKey($Key)) { $FileContentMagic[$Key] } else { 'noSet' }
'NAME' = $item.'Nom'
'FIRSTNAME' = $item.'Prenom'
'SERVICE' = $item.'Service'
'Immeuble' = $item.'Immeuble'
'Niveau' = $item.'Niveau'
'Loc.' = $item.'Loc.'
'PDT' = $item.'PDT'
'Occ.' = $item.'Occ.'
'Site' = $item.'Site'
}
}
此外,只要您使用+=
连接数组,就会带来显着的性能损失。避免使用它是值得的,因为每个赋值创建一个新数组,使用新项复制整个数组,然后丢弃旧数组。这是非常低效的。
如果$FileContentMagic
包含重复的键,那么您应该更改HashTable的加载方式:
$FileContentMagic = @{}
Import-Csv -Path $FileContentMagicFileName | ForEach-Object {
$Key = $_.Matricule.Trim(), $_.Nom.Trim(), $_.Prenom.Trim() -join $Delimiter
if (!$FileContentMagic.ContainsKey($Key)) {
$Value = $_.IGG -join '/'
$FileContentMagic.Add($Key, $Value)
}
else {
$FileContentMagic[$Key] += '/' + ($_.IGG -join '/')
}
}
答案 1 :(得分:1)
我会简化这一点,但更改不应影响处理时间。我所做的唯一优化是将$ filechecktrue更改为更高内存效率的List。
不确定这实际上是否是脚本的慢速部分。这需要$fileContentMagic
成为非常大的数组。
$filechecktrue = New-Object System.Collections.ArrayList
foreach ($item in $fileContentIMM)
{
try
{
$Matricule = $item.'Matricule'
$name = $item.'Nom'
$firstname = $item.'Prenom'
# find first matching row in $fileContentMagic using wildcard
$objMatch = $fileContentMagic | Where-Object { $_.'Matricule' -eq $Matricule -and $_.'NOM' -eq $name -and $_.'PRENOM' -eq $firstname}
#Create results object with common properties
$o += [pscustomobject]@{
'MATRICULE' = $item.'Matricule'
'IGG' = 'noSet'
'NAME' = $item.'Nom'
'FIRSTNAME' = $item.'Prenom'
'SERVICE' = $item.'Service'
'Immeuble'= $item.'Immeuble'
'Niveau' = $item.'Niveau'
'Loc.' = $item.'Loc.'
'PDT' = $item.'PDT'
'Occ.' = $item.'Occ.'
'Site' = $item.'Site'
}
##### check if any match found
if ($objMatch)
{
#if not null, set IGG value. No need for foreach as $item is already a "foreach-value".
$o.IGG = ($objMatch.'IGG' -join '/')
}
#Add result to arraylist
$filechecktrue.Add($o)
}
catch
{
"ERROR: Problem reading line - skipping :" | Out-File $LogFile -Append -Force
$item.nom + $item.prenom + $item.service| Out-File $LogFile -Append -Force
}
}
答案 2 :(得分:0)
你的第一个foreach在每次迭代时返回一个$ item-object,所以再次在代码块内的$ item上使用foreach(两次)是无稽之谈。
尝试此操作(删除冗余):
foreach ($item in $fileContentIMM) {
try {
# find first matching row in $fileContentMagic using wildcard
$objMatch = $fileContentMagic | where { $_.'Matricule' eq $item.'Matricule'
-and $_.'NOM' -eq $item.'Nom'
-and $_.'PRENOM' -eq $item.'Prenom'}
##### check if any match found
if ($objMatch -eq $null) {
$IGG = 'noSet'
} else {
$IGG = ($objMatch.'IGG' -join '/')
}
$filechecktrue += [pscustomobject]@{
'MATRICULE' = $item.'Matricule'
'IGG' = $IGG
'NAME' = $item.'Nom'
'FIRSTNAME' = $item.'Prenom'
'SERVICE' = $item.'Service'
'Immeuble'= $item.'Immeuble'
'Niveau' = $item.'Niveau'
'Loc.' = $item.'Loc.'
'PDT' = $item.'PDT'
'Occ.' = $item.'Occ.'
'Site' = $item.'Site'
} catch {
"ERROR: Problem reading line - skipping :" | Out-File $LogFile -Append -Force
$item.nom + $item.prenom + $item.service| Out-File $LogFile -Append -Force
}
}