iRon7 / Join-Object

Combines two objects lists based on a related property between them.
MIT License
107 stars 13 forks source link

FullJoin doesn't work properly when joining multiple array when one of the array is empty #28

Closed sanjeev40084 closed 3 years ago

sanjeev40084 commented 3 years ago

Create 2 new arrays and add data on first array and don't add any data on second array.

$arrayList1 = @()
$arrayList2 = @()

$arrayList1 += "james"
$arrayList1 += "henry"

$arrayList1 |FullJoin $arrayList2 -Name arrayList1, arrayList2

The output looks like this:

james
henry

Expected:

arrayList1 arrayList2
james
henry
iRon7 commented 3 years ago

Thanks, for the information. I looks like a bug. I do have some tests for empty arrays included but unfortunately only on inner joins. I need some time to fix this.

iRon7 commented 3 years ago

At second sight, this issue not really a bug in this context but rather a high-level design limitation. Let me explain...

First of all, there are a few features in this Join cmdlet that are related to this issue:

This features are inferieur to the main purpose of this cmdlet: combine two object lists based on a related property between them. Nevertheless, I will do whatever is possible to support them all-in-one.

Taken:

$a = @('a1', 'a2')
$b = @('b1', 'b2')
$c = @('c1', 'c2')
$d = @('d1', 'd2')

I can join these arrays like:

$ab = $a |Join $b
$cd = $c |Join $c
$abcd = $ab |Join $cd
$abcd |% { "$_" }
a1 b1 c1 d1
a2 b2 c2 d2

Where:

Now question yourself: what exactly is @()? It is an array with no dimensions: an array with zero rows and zero columns. Implying that there is no way to determine how many columns it actually is supposed to have when it is filled.

Which changes the question to: how do I create an array with 1 (or more) columns but no rows? You can do that using initiators like: [Object[]] where you define that the array has a single column that contains a list of (or zero) objects.

This was not working in previous versions either but implemented from version 3.5.4. Meaning you can now do this:

$arrayList1 = [Object[]]@('james', 'henry')
$arrayList2 = [Object[]]@()

$arrayList1 |FullJoin $arrayList2 -Name arrayList1, arrayList2

arrayList1 arrayList2
---------- ----------
james
henry

Note: Due to the nature of the PowerShell pipeline, @() |... (or [Object[]]@() |...) will not process any items, meaning:

[Object[]]@() |% { "Result" }

Will not show any result. In other words, if also the left object lists is possibly empty (in an outer join), you will to supply the lists as arguments:

$arrayList1 = [Object[]]@()
$arrayList2 = [Object[]]@('james', 'henry')

FullJoin -Left $arrayList1 -Right $arrayList2 -Name arrayList1, arrayList2

arrayList1 arrayList2
---------- ----------
           james
           henry
sanjeev40084 commented 3 years ago

@iRon7 if i have more than two arraylist what is the command to display all arraylist result? i tried this but it only showed $arrayList2 and $arrayList3

FullJoin -Left $arrayList1 -Right $arrayList2, $arrayList3 -Name arrayList1, arrayList2, arrayList3
arrayList2 arrayList3
james test
henry

arraylist = didn't had value arraylist2 = james, henry arraylist3 = test

iRon7 commented 3 years ago

The easiest way to do this is chaining the join commands:

$arraylist1 = @()
$arraylist2 = 'james', 'henry'
$arraylist3 = 'test'

FullJoin -Left ([Object[]]$arrayList1) -Right $arrayList2 |FullJoin $arrayList3 -Name arrayList1, arrayList2, arrayList3

arrayList1 arrayList2 arrayList3
---------- ---------- ----------
            james      test
            henry

Note that you have to prefix the empty array with an initiator like [Object[]] to give it any dimensions (as fixed and explained in this original issue).