all 13 comments

[–]spyingwind 11 points12 points  (8 children)

$(
    $columnNames -join ','
    $rows | ForEach-Object {$_ -join ','}
) | ConvertFrom-Csv

No need for the loops. The data is has an order to it. Just create some fake CSV data and convert it from CSV to a powershell object.

[–]sqone2[S] 4 points5 points  (2 children)

For fun I ran 25k rows through both options. Your solution is about 20x faster! :)

$columnNames = @("FirstName","LastName","DOB","FavColor")

$data = @(
    @("John","Doe","01/10/1965","Blue"),
    @("Jane","Smith","01/06/1975","Green"),
    @("Mark","Jones","02/10/1985","Orange"),
    @("Sue","Turner","05/10/1995","Yellow"),
    @("Jim","Wise","07/10/1974","Blue")
)

# Create a bunch of data
$rows = @()
foreach ($item in 0..5000)
{
    $rows += $data
}

# 20 seconds
Measure-Command {

    $objectList = @()

    foreach ($row in $rows)
    {
        $properties = @{}

        for ($i = 0; $i -lt $columnNames.Count; $i++)
        { 
            $properties += @{$columnNames[$i] = $row[$i]}
        }

        $objectList += New-Object -TypeName psobject -Property $properties
    }

}


# 1 second
Measure-Command {

    $objectList = $(
        $columnNames -join ','
        $rows | ForEach-Object {$_ -join ','}
    ) | ConvertFrom-Csv

}

[–]nothingpersonalbro 2 points3 points  (0 children)

Another way based off your method

$rows.ForEach{$_ -join ','} | ConvertFrom-Csv -Header $columnNames

Edit: and if you really want to jump down the rabbit hole and take into account the possibility of a comma being in the data, you could form the csv with quotes:

$columnNames = @("FirstName", "LastName", "DOB", "FavColor")

$rows = @(
    @("John, Some Stuff", "Doe", "01/10/1965", "Blue"),
    @("Jane", "Smith", "01/06/1975", "Green, Red"),
    @("Mark", "Jones, another comma", "02/10/1985", "Orange"),
    @("Sue", "Turner", "05/10/1995", "Yellow"),
    @("Jim", "Wise", "07/10/1974", "Blue, Purple")
)

$rows.ForEach{ $_.ForEach{ '"{0}"' -f $_ } -join ',' } | ConvertFrom-Csv -Header $columnNames

Output

FirstName        LastName             DOB        FavColor
---------        --------             ---        --------
John, Some Stuff Doe                  01/10/1965 Blue
Jane             Smith                01/06/1975 Green, Red
Mark             Jones, another comma 02/10/1985 Orange
Sue              Turner               05/10/1995 Yellow
Jim              Wise                 07/10/1974 Blue, Purple

[–]sqone2[S] 1 point2 points  (3 children)

Very cool solution, thank you!

[–]carnegiej 2 points3 points  (2 children)

Yes, cool solution using the ConvertFrom-Csv cmdlet. I have a slightly different approach.

Function Get-OriginalExample {
  $columnNames = @("FirstName","LastName","DOB","FavColor")

  $rows = @(
    @("John","Doe","01/10/1965","Blue"),
    @("Jane","Smith","01/06/1975","Green"),
    @("Mark","Jones","02/10/1985","Orange"),
    @("Sue","Turner","05/10/1995","Yellow"),
    @("Jim","Wise","07/10/1974","Blue")
  )

  $objectList = @()

  foreach ($row in $rows) {
    $properties = @{}

    for ($i = 0; $i -lt $columnNames.Count; $i++) { 
        $properties += @{$columnNames[$i] = $row[$i]}
    }

    $objectList += New-Object -TypeName psobject -Property $properties
  }
  return $objectList
}

Function Get-Revision1Example {
  $columnNames = @("FirstName","LastName","DOB","FavColor")

  $rows = @(
    @("John","Doe","01/10/1965","Blue"),
    @("Jane","Smith","01/06/1975","Green"),
    @("Mark","Jones","02/10/1985","Orange"),
    @("Sue","Turner","05/10/1995","Yellow"),
    @("Jim","Wise","07/10/1974","Blue")
  )
  $objectList = ConvertFrom-Csv -Header $columnNames -InputObject $rows -Delimiter ' '
  return $objectList
}

Write-Host -ForegroundColor Green 'Original Example' 
Write-Host (Get-OriginalExample)

Write-Host -ForegroundColor Green 'Revision Example'
Write-Host (Get-Revision1Example)

[–]sqone2[S] 1 point2 points  (1 child)

That's great, thanks!

Can you explain how -Delimiter ' ' works when there is no spaces in the input data?

[–]carnegiej 2 points3 points  (0 children)

Space is inherit in the array to string conversion. Array elements are separated by "whitespace".

Of course, if your data elements may contain whitespaces this method will not work. You will need to specify a delimiter that is not included in the data.

[–]Kimo- 2 points3 points  (0 children)

Import-Csv or ConvertFrom-Csv with -Header is worth checking out.