Stupid PSH Trick: Diffing Lists
I have two lists of strings. One contains values that must be in the output. The other is the actual output, Split() into strings. I need to ensure all elements in the first list are in the second. Optionally, I may need to ensure the second list only contains elements of the first. The problem with [array]::IndexOf() is that it is case sensitive, and our use case mighgt be case-insensitive.
One way is to canonicalize both lists to the same case, then sort them, and lastly, join them to compare and see if they're the same.
$string1 = [string]::Join($delim, ($list1 | % { $_.ToLower()}));
$string2 = [string]::Join($delim, ($list2 | % { $_.ToLower()}));
$string1 -eq $string 2;
Or another way is to canonicalize both lists to the same case, then use [array]::IndexOf() to ensure all elements in $list1 are in $list2, and vice versa.
function Test-SubSet {
param ( [String[]]$list1, [String[]]$list2);
$lcList1 = $list1 | % { $_.ToLower; }
$lcList2 = $list2 | % { $_.ToLower; }
$pass = $true;
foreach ($element in $lcList1) {
if ([array]::IndexOf($lcList2, $element) -eq -1) {
$pass= $false;
break;
}
}
$pass;
}
My favourite doesn't require canonicalization, but it doesn't handle duplicate entries very well. I like it because it uses [Hashatables].
$list1Hash = @{};
$list1 | % { $list1Hash[$_] = $true; }
$list2 | % {
if ($list1Hash[$_]) {
$list1Hash.Remove($_);
} else {
Log-Problem "$_ is in list2 but not in list1";
}
}
$list1Hash.Keys | sort | % { Log-Problem "$_ is in list1 but not in list2";
List 1 goes into a hash with $true as the element values. Anything repeated in List 1 is ignored. Anything repeated in List 2 will case it to be marked as an incorrect entry.