PowerShell 脚本效率建议



>我有一个电话.csv,其中包含 2020 年 1 月和 2 月某些日子的编译数据,每一行都有在每个状态上花费的日期和时间,因为有人在文件的每个状态都有一行的那一天使用不同的状态,我的脚本应该遍历文件,找到最小日期,然后开始在新文件上保存同一天的所有数据, 所以我将以 01-01-2020、02-01-2020 等的一个文件结束,但它运行了 15 个小时,它仍然是 1/22。

我用于日期的列称为"DateFull",这是脚本

write-host "opening file" 
$AT= import-csv “C:UsersxxxxxxDesktopSignOnOff_20200101_20200204.csv” 
write-host "parsing and sorting file" 
$go= $AT| ForEach-Object {
$_.DateFull= (Get-Date $_.DateFull).ToString("M/d/yyyy")
$_
}

Write-Host "prep day"
$min = $AT | Measure-Object -Property Datefull  -Minimum  
Write-Host $min
$dateString =  [datetime] $min.Minimum
Write-host $datestring
write-host "Setup dates"
$start = $DateString - $today
$start = $start.Days
For ($i=$start; $i -lt 0; $i++)  {
$date = get-date
$loaddate = $date.AddDays($i) 
$DateStr = $loadDate.ToString("M/d/yyyy")
$now = Get-Date -Format HH:mm:ss
write-host $datestr " " $now
#Install-Module ImportExcel #optional import if you dont have the module already
$Check = $at | where {$_.'DateFull' -eq $datestr} 
write-host $check.count
if ($check.count -eq 0 ){}
else {$AT | where {$_.'DateFull' -eq $datestr} | Export-Csv "C:UsersxxxxxDesktopsignonoffSignOnOff_$(get-date (get-date).addDays($i) -f yyyyMMdd).csv" -NoTypeInformation}
}
$at = '' 

第一个循环没有多大意义。它循环浏览 CSV 内容并将每行的日期转换为不同的格式。之后,$go再也不使用。

$go= $AT| ForEach-Object {
$_.DateFull= (Get-Date $_.DateFull).ToString("M/d/yyyy")
$_
}

稍后,尝试从未初始化的变量中计算值。$today从未定义。

$start = $DateString - $today

然而,看起来你想用天来计算出最年长的记录有多老。

然后有一个从负天数到零的循环。在每次迭代期间,将搜索整个 CSV:

$Check = $at | where {$_.'DateFull' -eq $datestr} 

如果有 30天和 15 000 行,则有 30*15000 = 450 000 次迭代。这具有 O(n^2( 的复杂性,这意味着即使相对较少的天数和行数,运行时也会达到很高的水平。

下一部分是再次处理相同的数组:

else {$AT | where {$_.'DateFull' -eq $datestr

好吧,搜索条件完全相同,但现在结果被发送到一个文件。这有一个副作用,即使您的工作加倍。尽管如此,O(2n^2( => O(n^2(,所以至少运行时不会以立方或更差的速度增长。

至于如何解决这个问题,有几件事。如果根据日期对 CSV 进行排序,则之后只需一次运行即可对其进行处理。

$at = $at | sort -Property datefull

然后,迭代每一行。由于行是按升序排列的,因此第一行是最早的。对于每一行,检查日期是否已更改。如果没有,请将其添加到缓冲区。如果有,请保存旧缓冲区并创建一个新缓冲区。

此示例不会转换 yyyyMMdd 格式的文件名,它假定只有两列foodatefull如下所示,

$sb = new-object text.stringbuilder
# What's the first date?
$current = $at[0]
# Loop through sorted data
for($i = 0; $i -lt $at.Count; ++$i) {
# Are we on next date?
if ($at[$i].DateFull -gt $current.datefull) {
# Save the buffer
$file = $("c:tempOnOff_{0}.csv" -f ($current.datefull -replace '/', '.') )
set-content $file $sb.tostring()
# Pick the current date
$current = $at[$i]
# Create new buffer and save data there
$sb = new-object text.stringbuilder
[void]$sb.AppendLine(("{0},{1}" -f $at[$i].foo, $at[$i].datefull))    
} else {
[void]$sb.AppendLine(("{0},{1}" -f $at[$i].foo, $at[$i].datefull))    
}
}
# Save the final buffer
$file = $("c:tempOnOff_{0}.csv" -f ($current.datefull -replace '/', '.') )
set-content $file $sb.tostring()

最新更新