[英]How can I remove duplicates in Powershell without running out of memory?
我目前正在Windows Powershell中使用此命令從簡單的1行CSV中刪除重復項。
gc combine.csv | sort | get-unique > tags.cs
每當我在一個150mb的CSV(2000萬行猜測 )上運行它時,任務管理器會顯示Powershell占用所有可用內存(32GB)然后使用虛擬內存。 我也讓腳本運行了大約一個小時,但它沒有完成。 我發現這很奇怪,因為在excel中,通常需要幾秒鍾才能從我的1M行CSVS中刪除重復項。 有關如何處理這個的任何建議?
你可以嘗試:
Get-Content combine.csv -ReadCount 1000 |
foreach-object { $_ } |
Sort-Object -Unique |
Set-Content tags.cs
( gc combine.csv -read 1kb | % { $_ } | sort -uniq | sc tags.cs
)
但我認為你會遇到同樣的問題。 如果您想要更快的結果,並且它們不需要排序,則只需要重復免費:
$Lines = [System.Collections.Generic.HashSet[string]]::new()
$Lines.UnionWith([string[]][System.IO.File]::ReadAllLines('c:\path\to\combine.csv'))
[System.IO.File]::WriteAllLines('c:\path\to\tags.cs', $Lines)
這是我在23秒內測試20M隨機數文件和~1.5GB內存。 如果它們確實需要排序,請使用SortedSet
而不是HashSet
,它在5分鍾內運行並且<2GB內存。 雖然您的代碼仍在運行,目前已通過15GB。
編輯:tiberriver256評論說, [System.IO.File]::ReadLines
,而不是ReadAllLines
可以前的文件完成了讀取流傳輸; 它返回一個枚舉器而不是所有行的最終數組。 在HashSet案例中,這會將運行時間從12.5秒降低到11.5秒 - 它變化太大而無法確定,但它似乎有所幫助。
Excel旨在處理有效的文件(顯然?我實際上有點驚訝)。
您的代碼的主要問題是您正在對它進行排序。 我知道你這樣做是因為Get-Unique
需要它,但Sort-Object
工作方式是它需要收集內存中發送到它的每個項目(在這種情況下,文件的每一行)以便實際做那種。 與文件不同,它不只是將其存儲為平面內存,而是將其存儲為N個字符串,其中N是文件中的行數,以及這些內存中字符串的所有開銷。 正如TessellatingHeckler指出的那樣,它似乎與排序有關,而不是存儲!
您可能希望確定給定的行在處理時是否唯一,因此您可以立即丟棄它。
為此,我會推薦套裝。 特別是一個HashSet,或者,如果你真的需要它排序,一個SortedSet 。
您的代碼的簡單轉換:
Get-Content combine.csv |
ForEach-Object -Begin {
$h = [System.Collections.Generic.HashSet[String]]::new()
} -Process {
if ($h.Add($_)) {
$_
}
} |
Set-Content tags.cs
對我來說,在大約650 MB的文件上進行測試,其中只有26個是獨一無二的,只需要超過一分鍾,並且沒有明顯影響RAM。
大約一半行獨特的同一文件大約需要2分鍾,並使用大約2 GB的RAM(使用SortedSet
需要2.5分鍾以上,大約2.4 GB)。
同樣的后一個文件,即使簡化了| sort | gu
| sort | gu
| sort | gu
to | sort -Unique
| sort -Unique
在~10秒內使用超過5 GB的RAM。
如果你開始使用StreamReader.ReadLine
和for
循環以及其他一些東西,你可能會擠出更多的性能,但我會為你留下一個練習。
似乎在大多數實現中,在最好的情況下,使用的RAM量將高度依賴於有多少項是唯一的(更多唯一項意味着更多RAM)。
Get-Content和stdio >
都很慢。 .Net可能會給你更好的表現。
嘗試:
$stream = [System.IO.StreamWriter] "tags.csv"
[System.IO.File]::ReadLines("combine.csv") | get-unique | sort | % { $Stream.writeline($_) }
$Stream.close()
使用4列1,000,000行csv在我自己的盒子上測試我在22秒時達到了650MB的內存利用率。 使用get-content和>
運行相同的csv是2GB內存和60秒。
從這里的類似問題中獲得一些額外的詭計( 在PowerShell中排序非常大的文本文件 ),您可以通過將數據轉換為哈希集來獲取唯一值,然后到列表並運行sort方法來進一步減少時間,因為這似乎是比PowerShell的Sort-Object快一點。
$stream = [System.IO.StreamWriter] "tags.csv"
$UniqueItems = [system.collections.generic.list[string]]([System.Collections.Generic.HashSet[string]]([System.IO.File]::ReadLines("combine.csv")))
$UniqueItems.sort()
$UniqueItems | % { $Stream.writeline($_) }
$Stream.close()
在我的同一數據集上使用它,我能夠在1秒鍾內完成,內存使用量為144MB。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.