【问题标题】:Powershell - Insert column in between specific columns in csv filePowershell - 在 csv 文件的特定列之间插入列
【发布时间】:2016-01-13 21:36:46
【问题描述】:

我有 2 个 csv 文件

第一个文件:

firstName,secondName
1234,Value1
2345,Value1
3456,Value1
4567,Value3
7645,Value3

第二个文件:

firstName,fileSplitter,Csv2ColumnOne,Csv2ColumnTwo,Csv2ColumnThree
1234,,1234,abc,Value1
1234,,1234,asd,Value1
3456,,3456,qwe,Value1
4567,,4567,mnb,Value1

我想在firstNamefileSplitter 列之间的第二个文件中插入列secondName

结果应该是这样的:

firstName,secondName,fileSplitter,Csv2ColumnOne,Csv2ColumnTwo,Csv2ColumnThree
1234,Value1,,1234,abc,Value1
1234,Value1,,1234,asd,Value1
3456,Value1,,3456,qwe,Value1
4567,Value3,,4567,mnb,Value1

我正在尝试以下代码:

Function InsertColumnInBetweenColumns
{
Param ($FirstFileFirstColumnTitle, $firstFile, [string]$1stColumnName, [string]$2ndColumnName, [string]$columnMergedFileBeforeInput)

Write-Host "Creating hash table with columns values `"$1stColumnName`" `"$2ndColumnName`" From $OimFileWithMatches"
$hashFirstFileTwoColumns = @{}
Import-Csv $firstFile | ForEach-Object {$hashFirstFileTwoColumns[$_.$1stColumnName] = $_.$2ndColumnName}
Write-Host "Complete."

Write-Host "Appending Merge file with column `"$2ndColumnName`" from file $secondCsvFileWithLocalPath"
Import-Csv $outputCsvFileWithLocalPath | Select-Object $columnMergedFileBeforeInput, @{n=$2ndColumnName; e={
if ($hashFirstFileTwoColumns.ContainsKey($_.$FirstFileFirstColumnTitle)) {
    $hashFirstFileTwoColumns[$_.$FirstFileFirstColumnTitle]
} Else {
    'Not Found'
}}}, * | Export-Csv "$outputCsvFileWithLocalPath-temp" -NoType -Force
Move-Item "$outputCsvFileWithLocalPath-temp" $outputCsvFileWithLocalPath -Force
Write-Host "Complete."
Write-Host ""
}

该函数将在第一个文件中找到的每一列的 for 循环中调用(可以包含不定数字)。为了测试,我只使用第一个文件中的 2 列。

我收到一个错误输出,结果如下:

Select : Property cannot be processed because property "firstName" already exists.
At C:\Scripts\Tests\Compare2CsvFilesOutput1WithMatchesOnly.ps1:490 char:43
+     Import-Csv $outputCsvFileWithLocalPath | Select $columnMergedFileBeforeInput, @ ...
+                                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (@{firstName=L...ntName=asdfas}:PSObject) [Select-Object], PSArgume
   ntException
    + FullyQualifiedErrorId : AlreadyExistingUserSpecifiedPropertyNoExpand,Microsoft.PowerShell.Commands.SelectObjectC
   ommand

我知道问题出在Select-Object $columnMergedFileBeforeInput, 的位置。

如何让循环语句在前列之间插入列(指定名称),并使用* 附加其余列?

更新

仅供参考,将这一行 Select-Object $columnMergedFileBeforeInput, @{n=$2ndColumnName..... 更改为这一行 Select-Object @{n=$2ndColumnName..... 有效,它只是无序地附加列。这就是我试图在两者之间插入列的原因。也许如果我这样做但使用 for 循环向后插入列,这将工作......

【问题讨论】:

  • 您的预期输出没有意义。文件 1 有 5 条记录,最后一条是指 Value37645 关联。文件 2 有 4 条记录,并且没有引用其中任何一个值,但不知何故,您的预期输出包括 Value3 和第四条记录。请用更合理的例子更新问题。
  • 您只是逐行进行吗?与 File1 中的 Record 2 一样,无论内容如何,​​都会与 File2 中的 Record 2 合并?两个文件的记录数是否相同?这可能是For($i=0;$i -lt $file1.count;$i++){} 循环的工作。
  • 更新了第一个有问题的文件。两个文件中的记录数量可以相同也可以不同。
  • 您的错误表明您试图拥有两个名称为“firstname”的属性。扩展变量后,您似乎正在有效地执行以下操作:Select firstname,firstname,* 因此,如果属性名称存在冲突,应该赢取什么?
  • 是的,firstName 列之前已添加到 test2.csv 文件中,以将值与Csv2ColumnOne 列匹配。现在找到的值匹配已添加为 test2.csv 文件中的第一列 firstName,我们需要插入 test1.csv 文件中的第二列以匹配 test2.csv 中第一列 firstName 中的行.

标签: powershell powershell-3.0


【解决方案1】:

不确定这是否是最有效的方法,但它应该可以解决问题。它只是将属性添加到 file2 的记录中,然后重新排序输出,因此 secondName 是第二列。您也可以在需要时将结果输出到 csv (ConvertTo-Csv)。

$file1 = Import-Csv -Path file1.csv
$file2 = Import-Csv -Path file2.csv

$results = @()
ForEach ($record In $file2) {
   Add-Member -InputObject $record -MemberType NoteProperty -Name secondName -Value $($file1 | ? { $_.firstName -eq $record.firstName } | Select -ExpandProperty secondName)
   $results += $record
}

$results | Select-Object -Property firstName,secondName,fileSplitter,Csv2ColumnOne,Csv2ColumnTwo,Csv2ColumnThree

【讨论】:

  • 问题是如果第一列中的值乱序,这将打印值不匹配。此外,由于两个文件的列名和列数都可以更改,因此无法对这些值进行硬编码。
  • 此条件应处理乱序的行:-Value $($file1 | ? { $_.firstName -eq $record.firstName } | Select -ExpandProperty secondName)。也可以处理没有列的数据。一种方法是 Import-Csv-Header 属性
  • 但是,如果列乱序,并且您不知道哪一列是哪一列,因为它们也没有标题 - 这是一个问题。
  • 确实,这就是为什么使用 get-content 非常麻烦,我更喜欢 import-csv 方法。我用一个发现更新了我的问题。可能想看看。
【解决方案2】:

我创建了以下函数。它的作用是找到匹配项(在本例中为“名字”)并将匹配的列名添加到新数组中匹配的列名之后(用我蹩脚的英语很难解释)。

function Add-ColumnAfterMatchingColumn{
[CmdletBinding()]
param(
    [string]$MainFile,
    [string]$MatchingFile,
    [string]$MatchColumnName,
    [string]$MatchingColumnName
)

# Import data from two files
$file1 = Import-Csv -Path $MainFile
$file2 = Import-Csv -Path $MatchingFile

# Find column names and order them
$columnnames = $file2 | gm | where {$_.MemberType -like "NoteProperty"} | Select Name | %{$_.Name}
[array]::Reverse($columnnames)

# Find $MatchColumnName index and put the $MatchingColumnName after it
$MatchColumnNameIndex = [array]::IndexOf($columnnames, $MatchColumnName)
if($MatchColumnNameIndex -eq -1){
    $MatchColumnNameIndex = 0
}
$columnnames = $columnnames[0..$MatchColumnNameIndex] + $MatchingColumnName + $columnnames[($MatchColumnNameIndex+1)..($columnnames.Length -1)]

$returnObject = @()
foreach ($item in $file2){
    # Find corresponding value MatchingColumnName in $file1 and add it to the current item
    $item | Add-Member -Name "$MatchingColumnName" -Value ($file1 | ?{$_."$($MatchColumnName)" -eq $item."$($MatchColumnName)"})."$MatchingColumnName" -MemberType NoteProperty

    # Add current item to the returnObject array, in the correct order
    $newItem = New-Object psobject
    foreach ($columnname in [string[]]$columnnames){
        $newItem  | Add-Member -Name $columnname -Value $item."$columnname" -MemberType NoteProperty 
    }
    $returnObject += $newItem
}
return $returnObject
}

当你运行这个函数时,你会得到以下输出:

Add-ColumnAfterMatchingColumn -MainFile C:\Temp\file1.csv -MatchingFile C:\Temp\file2.csv -MatchColumnName "firstname" -MatchingColumnName "secondname" | ft

firstName secondname fileSplitter Csv2ColumnTwo Csv2ColumnThree Csv2ColumnOne
--------- ---------- ------------ ------------- --------------- -------------
1234      Value1                  abc           Value1          1234         
1234      Value1                  asd           Value1          1234         
3456      Value1                  qwe           Value1          3456         
4567      Value3                  mnb           Value1          4567         

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-18
    • 2020-07-10
    • 2020-03-28
    相关资源
    最近更新 更多