Это идеальный практик корм, вы можете написать его несколько способов, ядро его является:
И с точки зрения PowerShell это имеет смысл, что вы организовать его:
Import-Csv | ForEach-Object { process one CSV row at a time } | Export-Csv
(as opposed to:
$foo = import-csv
$bar = @()
foreach ($line in $foo) {
#...
$bar += $line
}
which is workable but ugly and wasteful of memory and CPU and won't scale nicely)
ОК, так что мы имели дело со структурой чтения/процесса/записи часть. Теперь вы назначаете числовые значения в ведра.
0-10 11-20 21-30 31-40
\__/ \___/ \___/ \___/
или любых других диапазонах размеров/ковшах.
и этот рисунок кричат if/else
или switch
.
Итак, оставшаяся часть - это одна из 1. 2. 3. подходов, которые вы выбираете, где и как вы разделяете текст с цифр, и как вы назначаете числа в ведра.
Большая часть этого выбора касается читаемости и ваших предпочтений.
Ковши с началом и концом подразумевают двойной тест, такой как start -le $num -and $num -lt end
, а затем два кромочных корпуса имеют только один тест. Но ваши три ведра означают, что вам нужен двойной тест, а два - один тест.
if ($foo -gt 100)
elseif (51 -lt $foo -and $foo -le 100)
elseif ($foo -lt 50)
Посмотрите на этот мишмар if/elseif и на разовые/двойные тесты. Но поскольку ваши ведра ударил вверх против друг друга хорошо, вы можете использовать/злоупотребление падения сквозного тестирования, чтобы иметь:
if ($foo -gt 100) { big }
if ($foo -le 100) { medium }
if ($foo -le 50) { small }
OK, некоторые из них будут получать назначены «средний», а затем «маленький», но этот макет читать гораздо лучше, чтобы посмотреть, что он делает, не так ли?
И провал неявно происходит в switch
, если вы не остановите его, так что у него будут переключающие шкафы с или без break
, чтобы остановить провал.
Если вы выбираете, чтобы соответствовать текст первым, вы, вероятно, будет использовать регулярные выражения, чтобы идентифицировать вещи, которые не являются числами (backwardsly), так что я получаю это:
Import-Csv .\t.csv | ForEach-Object {
if ($_.Col03 -notmatch '^\d+$')
{
$_.Col01 = 'text'
}
else
{
if ([int]$_.Col03 -gt 100) { $_.Col01 = 'large' }
if ([int]$_.Col03 -le 100) { $_.Col01 = 'medium' }
if ([int]$_.Col03 -le 50) { $_.Col01 = 'small' }
}
$_
} # | Export-Csv out.csv -NoTypeInformation
Который является работоспособным , но э. Если вы сначала определите номера, вы можете использовать один и тот же шаблон регулярных выражений или указать инфраструктуру .Net для TryParse
, указав текст как число. Я получаю:
Import-Csv .\t.csv | ForEach-Object {
[int]$n = 0
if ([int]::TryParse($_.Col03, [ref]$n))
{
if ($n -gt 100) { $_.Col01 = 'large' }
if ($n -le 100) { $_.Col01 = 'medium' }
if ($n -le 50) { $_.Col01 = 'small' }
}
else
{
$_.Col01 = 'text'
}
$_
} # | Export-Csv out.csv -NoTypeInformation
Что не очень красиво. Перейти на регулярное выражение/переключатель проваливается комбо и я получаю:
Import-Csv .\t.csv | ForEach-Object {
switch -regex ($_)
{
{$_.Col03 -notmatch '^\d+$'} { $_.Col01 = 'text' ; break }
{[int]$_.Col03 -gt 100} { $_.Col01 = 'large' }
{[int]$_.Col03 -le 100} { $_.Col01 = 'medium' }
{[int]$_.Col03 -le 50 } { $_.Col01 = 'small' }
}
$_
} # | Export-Csv out.csv -NoTypeInformation
что вполне достаточно, но частичное ; break
/проваливаюсь просто ждем кого-то, чтобы делать ошибки при чтении его.И с помощью обработки исключений в потоке управления, я получаю это, (который я изменил, чтобы прочитать весь файл в память первого из обзорных вопросов с $_
внутри блока улова):
$Rows = foreach ($Row in Import-Csv .\t.csv)
{
try {
if ([int]$Row.Col03 -gt 100) { $Row.Col01 = 'large' }
if ([int]$Row.Col03 -le 100) { $Row.Col01 = 'medium' }
if ([int]$Row.Col03 -le 50) { $Row.Col01 = 'small' }
} catch {
$row.Col01 = 'text'
}
$row
}
$Rows # | Export-Csv out.csv -NoTypeInformation
Но все они делая в основном то же самое, и я не могу придумать более удобный способ сделать bucketing, поэтому все мои ответы в значительной степени одинаковы, даже если они выполняются через совершенно другой код.
Frode F использует PowerShell, назначаемый из if
, работает по-другому, но в этом подходе я не могу использовать проверку проскальзывания ковша - отсюда его использование if/elseif/if вместо if/if/if , Который является своего рода хорошо, и может быть отформатирован следующим образом:
$row.Col01 = if ( $n -le 50) { 'small' }
elseif (51 -lt $n -and $n -le 100) { 'medium' }
elseif (100 -lt $n ) { 'large' }
, а затем это понятнее они начала/конца диапазоны, а на самом деле, да мне нравится подход Фрод лучше всего, просто не отформатирован, как он отформатирован, и хочу я d прочитайте его ответ, прежде чем писать это.
Что вы пробовали? Может ли Col03 быть целыми или текстовыми? Средний и большой те же требования. –