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?

iRon
  • 20,463
  • 10
  • 53
  • 79
Witchayanin
  • 57
  • 2
  • 8
  • This is actually an old repeating issue, see [In Powershell, what's the best way to join two tables into one?](https://stackoverflow.com/a/45483110/1701026)). If you don't want to reinvent the wheel, you might use this [`Join-Object script`](https://www.powershellgallery.com/packages/Join)/[`Join-Object Module`](https://www.powershellgallery.com/packages/JoinModule): `$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 Date` – iRon Feb 03 '23 at 08:26

1 Answers1

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
    }
}
Santiago Squarzon
  • 41,465
  • 5
  • 14
  • 37