Vas*_*kin 3 linq datatable powershell
我有一个关于在 PowerShell 中使用 Linq 的问题。我不知道如何正确使用该Except方法
示例表:
$Arr = 1..1000
$Props = ("employeeID","FindName1","FindName2")
$Table1 = New-Object System.Data.DataTable "Table1"
$Props | ForEach-Object { $Table1.Columns.Add( $_ , [String]) | Out-Null }
ForEach ($Record in $Arr ) {
$Row = $Table1.NewRow()
$Row.employeeID = $Record.ToString("00000")
$Row.FindName1 = "UserName_" + $Record.ToString()
$Row.FindName2 = "String_" + $Record.ToString("00000000")
$Table1.Rows.Add($Row)
}
$Arr2 = 980..1111
$Props = ("employeeID","FindName1")
$Table2 = New-Object System.Data.DataTable "Table2"
$Props | ForEach-Object { $Table2.Columns.Add( $_ , [String]) | Out-Null }
ForEach ($Record in $Arr2 ) {
$Row = $Table2.NewRow()
$Row.employeeID = $Record.ToString("00000")
$Row.FindName1 = "UserName_" + $Record.ToString()
$Table2.Rows.Add($Row)
}
Run Code Online (Sandbox Code Playgroud)
作为工作的结果,我想从$table1FindName1 not in 中获取记录$Table2.FindName1,保留所有标题
尝试执行不会产生预期的结果。
$ExceptOut = [System.Linq.Enumerable]::Except($Table1.FindName1, $Table2.FindName1)
Run Code Online (Sandbox Code Playgroud)
正如我从文章中了解到的,我需要使用允许我在表中使用 LINQ 的方法创建自己的类。但我离编程还很远。或者也许还有其他一些类似于"NOT IN"SQL 的快速模拟。我希望得到帮助。谢谢。
要使(通用).Except()LINQ 方法工作,IEnumerable<T>作为参数传递的两个可枚举项 ( ) 必须:
TIEquatable<T>接口。PowerShell是看似无法找到合适的过载.Except()与[object[]]阵列由归国$Table1.FindName1和$Table2.FindName1,虽然这些阵列技术上满足上述要求-我不知道为什么。
但是,只需将这些数组转换为已经存在的数组即可[object[]]解决问题:
[Linq.Enumerable]::Except([object[]] $Table1.FindName1, [object[]] $Table2.FindName1)
Run Code Online (Sandbox Code Playgroud)
鉴于该.FindName1列最终包含strings,您也可以强制转换为[string[]],但在我的非正式测试中,这样做并没有再次提供性能,至少对于您的示例数据。
现在,如果您想在仅将列用于比较时返回整行.FindName1,事情会变得更加复杂:
您必须实现一个实现IEqualityComparer[T]接口的自定义比较器类。
您必须将.Rows数据表的集合转换为IEnumerable[DataRow],这需要通过反射调用 System.Linq.Enumerable.Cast() 方法。
[DataRow[]]转换为,但这会涉及将行集合转换为数组的效率低下。这是将自定义比较器类实现为 PowerShell 类的 PSv5+ 解决方案:
# A custom comparer class that compares two DataRow instances by their
# .FindName1 column.
class CustomTableComparer : Collections.Generic.IEqualityComparer[Data.DataRow] {
[bool] Equals([Data.DataRow] $x, [Data.DataRow] $y) {
return [string]::Equals($x.FindName1, $y.FindName1, 'Ordinal')
}
[int] GetHashCode([Data.DataRow] $row) {
# Note: Any two rows for which Equals() returns $true must return the same
# hash code. Because *ordinal, case-sensitive* string comparison is
# used above, it's sufficient to simply call .GetHashCode() on
# the .FindName1 property value, but that would have to be tweaked
# for other types of string comparisons.
return $row.FindName1.GetHashCode();
}
}
# Use reflection to get a reference to a .Cast() method instantiation
# that casts to IEnumerable<DataRow>.
$toIEnumerable = [Linq.Enumerable].GetMethod('Cast').MakeGenericMethod([Data.DataRow])
# Call .Except() with the casts and the custom comparer.
# Note the need to wrap the .Rows value in an aux. single-element
# array - (, ...) - for it to be treated as a single argument.
[Linq.Enumerable]::Except(
$toIEnumerable.Invoke($null, (, $Table1.Rows)),
$toIEnumerable.Invoke($null, (, $Table2.Rows)),
[CustomTableComparer]::new()
)
Run Code Online (Sandbox Code Playgroud)
这个 GitHub 问题建议让 LINQ 成为一流的 PowerShell 公民。
| 归档时间: |
|
| 查看次数: |
718 次 |
| 最近记录: |