2015-04-26 6 views
1

У меня есть CSV-файл с одним столбцом. В зависимости от того, сколько кодов ошибок имеет моя машина, этот столбец будет иметь различное количество кодов (до 10 под-столбцов - см. Пример ниже). Я хочу управлять этим CSV таким образом, чтобы выход был чистым списком уникальных кодов отказа что произошло.Удаление дубликатов из файла CSV с помощью PowerShell

Образец CSV-файл (sample.csv):

ActiveFaults 

00:1523 00:1345 00:1343 90:1344 

00:1523 00:1345 00:1343 90:1344 

00:1523 00:1345 00:1343 90:1344 

00:1523 00:1345 00:1343 90:1344 

00:1523 00:1345 00:1343 90:1344 90:5900 90:8988 

00:1523 00:1345 00:1343 90:1344 90:5900 90:8988 

BA:8797 BA: 1330 

Идеальный выход будет файл CSV в следующей форме:

IdealOutput.csv

UniqueActiveFaults 

00:1523 

00:1345 

00:1343 

90:1344 

90:5900 

90:8988 

BA:8797 

BA:1330 

Любые идеи, как это может быть сделано? Я пробовал несколько способов (используя -Sort, -Group и т. Д. ... но никто не работал по своему усмотрению) Спасибо.

ответ

3

Прекратите думать о файле как CSV.

Просто прочитал в одну строку, разделите его пробелами и по конвейеру к Sort-Object -Unique:

$Values = (Get-Content .\sample.csv -Raw) -split '\s+' | Where-Object {$_ -like '*:*'} 
"UniqueActiveFaults" |Out-File .\IdealOutput.csv 
$Values | Sort-Object -Unique | Out-File .\IdealOutput.csv 

оператор -split принимает регулярное выражение как его правого операнда, в этом случае \s+. \s является обобщающим для «пробелов» класса символов и + означает «матч 1 или более из предыдущих символов»

Если файл огромен, вы можете разделить обработку на куски с параметром ReadCount в первом заявлении:

Get-Content .\sample.csv -ReadCount 100 |ForEach-Object {$_ -split '\s+'} 

Если : присутствует в другом месте в документе, и желаемые значения всегда формы

[2 character prefix]:[numerical] 

вы могли бы сократить его, изменив Where-Object фильтр:

{$_ -match '.{2}:\d+'} 
+0

Я думаю, что файл имеет строку заголовка («ActiveFaults»). Также выходной файл имеет строку заголовка. В этом случае я думаю, что было бы разумно использовать 'import-csv' и' export-csv' inst'aed 'get-content' и' out-file'. –

+0

@ dan-gph Да, но если файл огромен, вы можете взять на себя огромные накладные расходы от создания объектов с единственным свойством UniqueActiveFaults, чтобы иметь возможность записать его обратно на диск с помощью 'Export-Csv'. Если файл имел несколько столбцов, это может иметь смысл, но в этом случае я не думаю, что компромисс стоит –

+0

Массивные накладные расходы? Это звучит как преждевременная оптимизация. Насколько нам известно, файлы имеют длину всего 10 строк. В соответствии с этим ваш код не соответствует требованиям, поскольку он не касается заголовков. Кстати, я не думаю, что -ReadCount поможет вам. В любом случае Sort-Object придется загружать весь файл в память. –

0
@ECHO Off 
SETLOCAL 
:: remove variables starting $ 
FOR /F "delims==" %%a In ('set $ 2^>Nul') DO SET "%%a=" 
(
ECHO(UniqueAciveFaults 
FOR /f "delims=" %%a IN (q29884835.txt) DO FOR %%b IN (%%a) DO SET "$%%b=y" 
FOR /f "delims=$=" %%a IN ('set $^|find ":"') DO ECHO(%%a 

)>u:\newfile.csv 

GOTO :EOF 

Я использовал файл с именем q29884835.txt, содержащий данные для моего тестирования.

Производит и: \ newfile.csv

Ну - это, очевидно, не PowerShell, но это работает.

Первый for очищает любые переменные среды начиная с $. Обычно их нет, поэтому, вероятно, это не требуется.

Вторая for строки читает файл, а затем для каждого элемента устанавливает variavle $elementcontents в y (тот факт, что он установлен на что-то важен, то что-то нет)

Третьей for линии выбирает, что часть набора $ переменные, которые содержат : и echo.

+0

Это впечатляет. Я снимаю с тебя шляпу. Но, откровенно говоря, этот код выглядит довольно ужасно. Почему бы не изучить PowerShell? ;) –

2

Поскольку Matthias не понравилось мое предложение, я покажу, что я имел в виду здесь:

Import-Csv .\Sample.csv | 
    % { $_.ActiveFaults -split '\s+' } | 
    Sort-Object -Unique | 
    Select-Object @{name='UniqueActiveFaults'; expr={ $_ } } | 
    Export-Csv IdealOutput.csv -NoTypeInformation 

Результат выглядит следующим образом:

"UniqueActiveFaults" 
"00:1343" 
"00:1345" 
"00:1523" 
"90:1344" 
"90:5900" 
"90:8988" 
"BA:1330" 
"BA:8797" 

Если вход был действительно огромный и выше код не мог справиться с этим эффективно, я бы попытался передать значения в .NET HashSet вместо Sort-Object.

+0

Doh! Не думал об использовании вычисленных выражений с помощью 'Select-Object'. В этом свете ваше предложение действительно имеет большой смысл, мне это, безусловно, нравится ;-) –

+0

Спасибо @Mathias, благодарю вас за основную идею. Надеюсь, мои комментарии не были слишком раздражающими :) –

Смежные вопросы