我有一个巨大的数组,里面有1 M+的名字,有些是字母数字,有些只是字母。
CSV:
id,firstname,lastname,email,email2,profession
100,Andeee,Michella,Andeee.Michella@yopmail.com,Andeee.Michella@gmail.com,police officer
101,Tybie,1Grobe,Tybie.Grobe@yopmail.com,Tybie.Grobe@gmail.com,worker
102,Fernande,Azeria,Fernande.Azeria@yopmail.com,Fernande.Azeria@gmail.com,developer
103,Lenna,Schenck,Lenna.Schenck@yopmail.com,Lenna.Schenck@gmail.com,police officer
104,4Marti,Brittani,Marti.Brittani@yopmail.com,Marti.Brittani@gmail.com,worker
105,Riannon,Aldric,Riannon.Aldric@yopmail.com,Riannon.Aldric@gmail.com,doctor
106,Corry,Nikaniki,Corry.Nikaniki@yopmail.com,Corry.Nikaniki@gmail.com,worker
107,Correy,Shama,Correy.Shama@yopmail.com,Correy.Shama@gmail.com,police officer
108,Marcy,Drus,Marcy.Drus@yopmail.com,Marcy.Drus@gmail.com,worker
109,Bill,Valerio,Bill.Valerio@yopmail.com,Bill.Valerio@gmail.com,worker
我不想对整个数组使用Sort-Oject或Sort,因为它花费的时间太长了。由于我的环境的限制,这需要在PowerShell中完成。
数组来自我从另一个powershell作业导出的csv。(我没有访问作业代码的权限,只有结果)。
下面是我从找到的Java方法创建的示例。它失败,并出现以下错误:The script failed due to call depth overflow.
$array = @("Ryan", "Kelly", "Alex", "Kyle", "Riley")
mergeSort $array
write-host $array
function mergeSort
{
param([string[]] $arr)
if($arr.length -ge 2){
#find mid-point
$left_len = [math]::floor([int32]$arr.length/2)
#declare array size of left of mid-point
$left = [string[]]::new($left_len);
#find mid-point
$right_len = [math]::ceiling([int32]($arr.Length - $arr.Length /2))
#declare array size right of mid-point
$right = [string[]]::new($right_len);
for ($i = 0; $i -lt $left_len.Length; $i++){
$left= $arr[$i]
}#for loop
for ($i = 0; $i -lt $right_len; $i++){
$right = $arr[$i +$arr.Length/2]
}
}#if($arr.length -ge 2)
mergeSort $left
mergeSort $right
merge ($arr, $left, $right)
}
function merge
{
param ([string[]] $result,[string[]] $left, [string[]] $right)
$i1 = 0
$12 = 0
for ($i = 0; $i -le $result.Length; $i++) {
if($i2 -gt $right.Length -or ($i1 -lt $left.Length -and $left[$i1].CompareTo($right[$i2]) -lt 0)) {
$result[$i] = $left[$i1]
$i1++
}
else {
$result[$i] = $right[$i2]
$i2++
}
}
$result.legnth
}
这是我根据大家的建议提出的最新解决方案:我想让这个工作在paralles,但它抛出错误:
$array = @('Ryan', 'Kelly', 'Alex', 'Kyle', 'Riley', '4test', 'test4', 'why', 'you', 'me', 'where', 'hello', 'jose', 'test',
'Jelly', 'Plex', 'Cyle', 'Miley', '5test', '3test4', 'who', 'Bou', 'We', 'There', 'Yellow', 'Pose', 'West')
$type = ("System.Collections.Generic.SortedSet"+'`'+"2") -as "Type"
$type = $type.MakeGenericType( @( ("System.string" -as "Type"), ("system.string" -as "Type") ) )
$sortedArray = [Activator]::CreateInstance($type, 10000)
$a, $b = ($array | Split-Collection -Count ([int]$array.length/2) | %{ $_ -join ',' })
$firstCollection = $a.Split(",")
$secondCollection = $b.Split(",")
$counter = 0
$counterHalf = $array.Length/2
1..$counterHalf| ForEach {
try {
$col1 = $firstCollection[$counter]
$sortedArray.Add($col1, $counter)
}
catch { "Out of bound col 1" }
try {
$col2 = $secondCollection[$counter]
$sortedArray.Add($col2, $counter)
}
catch { "Out of bound col 2" }
$counter++
}
$sortedArray
function Split-Collection {
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline=$true)] $Collection,
[Parameter(Mandatory=$true)][ValidateRange(1, 247483647)][int] $Count)
begin {
$Ctr = 0
$Arrays = @()
$TempArray = @()
}
process {
if (++$Ctr -eq $Count) {
$Ctr = 0
$Arrays += , @($TempArray + $_)
$TempArray = @()
return
}
$TempArray += $_
}
end {
if ($TempArray) { $Arrays += , $TempArray }
$Arrays
}
}
3条答案
按热度按时间2w3kk1z51#
FWIW,这是对最初关于让合并排序代码工作的问题的回答。不幸的是,它的性能不是很好,所以我不知道它是否真的能帮助你解决1 M+行的排序问题。
好消息
我对你原来的
mergeSort
做了一些调整,似乎可以修复它,至少对于你问题顶部的示例数组是这样。修复的大部分是错别字-请参阅BeyondCompare的屏幕截图,看看我所做的更改:
坏消息
很慢。
相比
也许它在你所说的数据规模下表现得更好,但我没有耐心测试它:-)
丑八怪
我还稍微调整了代码,以便在对右侧执行任何操作之前对左侧进行排序,这意味着它不需要使用太多内存。
这是更新后的样本,供后人参考。
需要特别调用的一件事是将输入数组转换为字符串:
如果没有强制转换,
$array
的类型是[System.Object[]]
,发生的情况是PowerShell将在内部创建一个新的 * 临时 *[string[]]
数组,将值复制到其中,然后对内部数组进行排序,但它 * 不会 * 将内部数组分配回$array
。不戴石膏试试看。
ff29svar2#
使用一个排序的字典,它的关键字是hash
dldeef673#
如果您在使用PowerShell时确实遇到了性能问题,则可以从阅读PowerShell scripting performance considerations开始
自顶向下实现
关于你的第一次尝试,你可能想要避免的一件事是递归函数,因为在PowerShell中调用函数是非常昂贵的,请参阅:What is the best way to reuse static code
特定错误脚本由于调用深度溢出而失败很可能是由于错误的检查,您应该停止递归调用,因此永远继续...
自底向上实现
关于你的第二次尝试,使用增加赋值运算符(
+=
)来创建一个集合是一个很常见的PowerShell性能问题,请参阅:Why should I avoid using the increase assignment operator (+=
) to create a collection合并排序原型
考虑到这两个问题,你可能会得到一个像这样的函数:
Demo
但是正如在@mclaytonhelpful answer中已经得出的结论,您不太可能用自制的PowerShell函数击败原生Sort-Object。
排序字典
无论如何,@jdwenghelpful answer中提到的使用
SortedDictionary<TKey,TValue>
Class的建议是击败原生Sort-Object
命令的更好候选。基准测试
我质疑你关于SortedDictionary“solution is linear”的评论,但我无法证明这一点。不管怎么说,我想最终还是要看实际的表现。
结果
分治
所以,现在我们知道
SortedDictionary
和SortedList
执行得最好,让我们看看是否可以将这些.Net任务划分到多个并行线程(CPU)上。并行排序原型
为此,我将需要
SortedList
(这是一个有点慢SortedDictionary
),因为我将需要能够索引到返回的列表。用法(健全性检查)
其中大量数据(例如
200.000
条目),合并并行排序例程确实看起来比单个进程SortedDictionary
更快: