Merging two arrays object into one array object in powershell [duplicate]
Asked Answered
Q

1

1

How can I merge two arrays object into one array object in PowerShell?

Array A

| Date  | AAA |
| 2023-01-01 | 1 |
| 2023-01-02 | 2 |
| 2023-01-03 | 3 |
| 2023-01-04 | 4 |
| 2023-01-05 | 5 |
| 2023-01-06 | 6 |
| 2023-01-07 | 7 |
| 2023-01-08 | 8 |
| 2023-01-09 | 9 |
| 2023-01-10 | 10 |

Array B

| D_Date  | BBB |
| 2023-01-06 | 6 |
| 2023-01-07 | 7 |
| 2023-01-08 | 8 |
| 2023-01-09 | 9 |
| 2023-01-10 | 10 |

Result

| Date  | AAA | BBB |
| 2023-01-01 | 1 | |
| 2023-01-02 | 2 | |
| 2023-01-03 | 3 | |
| 2023-01-04 | 4 | |
| 2023-01-05 | 5 | | 
| 2023-01-06 | 6 | 6 |
| 2023-01-07 | 7 | 7 |
| 2023-01-08 | 8 | 8 |
| 2023-01-09 | 9 | 9 |
| 2023-01-10 | 10 | 10 |

Here is my code example.

$listA = [pscustomobject]@(
    [pscustomobject]@{
        Date = Get-Date "2023-01-01"
        AAA = "1"
    }, [pscustomobject]@{
        Date = Get-Date "2023-01-02"
        AAA = "2"
    }, [pscustomobject]@{
        Date = Get-Date "2023-01-03"
        AAA = "3"
    }, [pscustomobject]@{
        Date = Get-Date "2023-01-04"
        AAA = "4"
    }, [pscustomobject]@{
        Date = Get-Date "2023-01-05"
        AAA = "5"
    }, [pscustomobject]@{
        Date = Get-Date "2023-01-06"
        AAA = "6"
    }, [pscustomobject]@{
        Date = Get-Date "2023-01-07"
        AAA = "7"
    }, [pscustomobject]@{
        Date = Get-Date "2023-01-08"
        AAA = "8"
    }, [pscustomobject]@{
        Date = Get-Date "2023-01-09"
        AAA = "9"
    }, [pscustomobject]@{
        Date = Get-Date "2023-01-10"
        AAA = "10"
    }
)

$listB = [pscustomobject]@(
    [pscustomobject]@{
        D_Date = Get-Date "2023-01-06"
        BBB = "6"
    }, [pscustomobject]@{
        D_Date = Get-Date "2023-01-07"
        BBB = "7"
    }, [pscustomobject]@{
        D_Date = Get-Date "2023-01-08"
        BBB = "8"
    }, [pscustomobject]@{
        D_Date = Get-Date "2023-01-09"
        BBB = "9"
    }, [pscustomobject]@{
        D_Date = Get-Date "2023-01-10"
        BBB = "10"
    }
)

foreach ($objA in $listA) {
    $objB = $listB | ? { $_.D_Date -eq $objA.Date }
    $objA | Add-Member -Name "BBB" -Type NoteProperty -Value $objB.BBB
}

I try to loop list A and assign property BBB with a value from list B but it seems very slow for the large array (4000-5000 objects) and in case of list B result is more than list A my code will not work, but I need to use the property "Date" instead of "D_Date".

How can I improve the performance and handle this case?

Quinte answered 3/2, 2023 at 4:13 Comment(1)
This is actually an old repeating issue, see In Powershell, what's the best way to join two tables into one?). If you don't want to reinvent the wheel, you might use this Join-Object script/Join-Object Module: $ListA |FullJoin $ListB -on Date -eq D_Date -Property Date, AAA, BBB or if the property on both sides is Date, it is simply: $ListA |FullJoin $ListB -on DateSuborbital
M
1

Using Group-Object might improve the performance of your code, the following groups both arrays by their Date / D_Date properties then enumerates each group constructing a new merged object:

$listA + $listB | Group-Object { if($value = $_.Date) { return $value }; $_.D_Date } |
    ForEach-Object {
        [pscustomobject]@{
            Date = $_.Name
            AAA  = $_.Group.AAA | Select-Object -First 1
            BBB  = $_.Group.BBB | Select-Object -First 1
        }
    }

Result from this would become like your expected outcome:

Date                  AAA BBB
----                  --- ---
1/1/2023 12:00:00 AM  1
1/2/2023 12:00:00 AM  2
1/3/2023 12:00:00 AM  3
1/4/2023 12:00:00 AM  4
1/5/2023 12:00:00 AM  5
1/6/2023 12:00:00 AM  6   6
1/7/2023 12:00:00 AM  7   7
1/8/2023 12:00:00 AM  8   8
1/9/2023 12:00:00 AM  9   9
1/10/2023 12:00:00 AM 10  10

The following is a similar, more manual way to approach it using an OrderedDictionary to group the objects which might be a bit more efficient:

$dict = [ordered]@{}
foreach($item in $listA + $listB) {
    $value = $item.Date
    if(-not $value) {
        $value = $item.D_Date
    }

    if(-not $dict.Contains($value)) {
        $dict[$value] = [System.Collections.Generic.List[object]]::new()
    }

    $dict[$value].Add($item)
}

foreach($pair in $dict.GetEnumerator()) {
    [pscustomobject]@{
        Date = $pair.Key
        AAA  = $pair.Value.AAA | Select-Object -First 1
        BBB  = $pair.Value.BBB | Select-Object -First 1
    }
}
Michi answered 3/2, 2023 at 5:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.