我们正在尝试优化一些代码,以尽可能快地从Array
中删除重复项。通常,可以通过将输入管道输送到Group-Object
然后仅使用Name
属性来轻松地完成此操作。但是我们希望避免使用管道,因为它速度较慢。
但是,我们尝试了以下代码:
[System.Collections.ArrayList]$uniqueFrom = @()
$From = @('A', 'A', 'B')
$From.Where({-not ($uniqueFrom.Contains($_))}).ForEach({
$uniqueFrom.Add($_)
})
$uniqueFrom
理论上,这应该可行。但是由于某种原因,输出不是预期的@('A', 'B')
。为什么不重新评估ArrayList
子句中的.where
?
答案 0 :(得分:2)
根据我的经验,可以通过使用DataView
来减少“管道过滤”以获得唯一值。如果要处理数组,则需要先将其转换为DataTable
,然后才能使用DataView
获取值。
例如
$arr = @('val1','val1','val1','val2','val1','val3'....)
$newDatatable = New-Object System.Data.Datatable
[void]$newDatatable.Columns.Add("FetchUniqueColumn")
foreach($e in $arr)
{
$row = $newDatatable.NewRow()
$row.Item('FetchUniqueColumn') = $e
$newDatatable.Rows.Add($row)
}
$filterDataView = New-Object System.Data.Dataview($newDatatable)
$UniqueDT = $filterDataView.ToTable($true,'FetchUniqueColumn')
$UniqueValues_array = $UniqueDT.Rows.FetchUniqueColumn
请注意,如果您输入的是DataTable
,则这样做的速度要快得多,因为在将DataView
的唯一值过滤器设置为$true
之前,您不必再进行转换。从数据视图创建$UniqueDT
数据表:
$UniqueDT = $filterDataView.ToTable($true,'FetchUniqueColumn')
通过从SQL查询具有3000行数据表的1列进行测试。 我的结果如下:
**With 1 column Data Table as input
Select -Unique - 300 ms
Using DataView - 21 ms
**With @() array as input (converted SQL results to array prior to benchmarking)
Select Unique - 262 ms
Using DataView - 106 ms
答案 1 :(得分:1)
免责声明 :在这个答案中,我只是在解释为什么当前代码无法正常工作,而不是尝试提供其他解决方案。有关解决方案,请检查the accepted answer。
为什么不重新评估.where子句中的ArrayList?
不应该这样做。它实际上是在这里过滤:
$From.Where({-not ($uniqueFrom.Contains($_))})
然后执行
$uniqueFrom.Add($_)
每个元素的。和你一样
[System.Collections.ArrayList]$uniqueFrom = @()
此数组为空,因此将为任何$false
返回$uniqueFrom.Contains($_)
要验证我上面写的是正确的,可以执行以下操作:
[System.Collections.ArrayList]$uniqueFrom = @()
$uniqueFrom.add("A")
$From.Where({-not ($uniqueFrom.Contains($_))}).ForEach({
$uniqueFrom.Add($_)
})
输出为A, B
(手动添加了A
,跳过了两个A
,因为此条目已存在于$uniqueFrom
中,B
已添加到{{ 1}})。