Частота слов элегантно в Powershell - PullRequest
0 голосов
/ 30 мая 2019

Дональд Кнут однажды получил задание написать грамотную программу, вычисляющую частоту слов в файле.

Прочитать текстовый файл, определить n наиболее часто используемых слов и распечатать отсортированные слова.список этих слов вместе с их частотами.

Даг Макилрой классно переписал 10 страниц Паскаля несколькими строчками sh:

tr -cs A-Za-z '\n' |
tr A-Z a-z |
sort |
uniq -c |
sort -rn |
sed ${1}q

В качестве небольшого упражнения я преобразовалэто для Powershell:

(-split ((Get-Content -Raw test.txt).ToLower() -replace '[^a-zA-Z]',' ')) |
  Group-Object |
  Sort-Object -Property count -Descending |
  Select-Object -First $Args[0] |
  Format-Table count, name

Мне нравится, что Powershell объединяет sort | uniq -c в один Group-Object.

Первая строка выглядит некрасиво, поэтому мне интересно, можно ли ее написать более элегантно?Может быть, есть способ загрузить файл с разделителем регулярных выражений?

Один очевидный способ сократить код - использовать псевдонимы, но это не способствует удобочитаемости.

Ответы [ 2 ]

1 голос
/ 30 мая 2019

Я бы сделал это так.

PS C:\users\me> Get-Content words.txt
One one
two
two
three,three.
two;two


PS C:\users\me> (Get-Content words.txt) -Split '\W' | Group-Object

Count Name                      Group
----- ----                      -----
    2 One                       {One, one}
    4 two                       {two, two, two, two}
    2 three                     {three, three}
    1                           {}

РЕДАКТИРОВАТЬ: некоторый код из Windows Powershell Брюса Пайетта в действии

# top 10 most frequent words, hash table
$s = gc songlist.txt
$s = [string]::join(" ", $s)
$words = $s.Split(" `t", [stringsplitoptions]::RemoveEmptyEntries)
$uniq = $words | sort -Unique
$words | % {$h=@{}} {$h[$_] += 1}
$frequency = $h.keys | sort {$h[$_]}
-1..-10 | %{ $frequency[$_]+" "+$h[$frequency[$_]]}

# or
$grouped = $words | group | sort count
$grouped[-1..-10]
0 голосов
/ 30 мая 2019

Спасибо js2010 и LotPings за важные советы. Чтобы документировать, что, вероятно, является лучшим решением:

$Input -split '\W+' |
  Group-Object -NoElement |
  Sort-Object count -Descending |
  Select-Object -First $Args[0]

То, что я узнал:

  • $Input содержит стандартный ввод. Это ближе к коду McIlroys, чем к некоторому файлу Get-Content.
  • split может принимать разделители регулярных выражений
  • параметр -NoElement позволяет мне избавиться от строки Format-Table.
...