Powershell, Get-Unique сносит уже уникальные, единичные объекты - PullRequest
3 голосов
/ 14 сентября 2011

Я собираю информацию из XML-файла и обрабатываю ее.Мои запросы либеральны, чтобы убедиться, что я получаю все возможные элементы, которые хочу.В результате можно получить дубликаты элементов в списке результатов (называемые $components).Я провел результат через Sort-Object, а затем Get-Unique, чтобы найти все уникальные объекты.Насколько я понимаю, один из каждого уникального объекта должен быть оставлен Get-Unique.Но это устраняет некоторые из уже уникальных объектов (объектов, которые не имеют дубликатов в исходном списке).

Вот упрощенный пример.Просто вставьте это в PowerShell или сохраните в файл ps1 и запустите (вывод показан ниже):

$xmlDoc = [xml]@'
<root>
    <component Id='component1'>
        <regkey Id='regkey1'/>
    </component>
    <component Id='component2'>
        <file Id='file1' />
    </component>
</root>
'@

$files = $xmlDoc.SelectNodes("//file[@Id='file1']")
$regkeys = $xmlDoc.SelectNodes("//regkey[@Id='regkey1']")
$components = $xmlDoc.SelectNodes("//component[@Id='component1'] | //component[@Id='component2']")
$components += $regkeys | Select-Object -ExpandProperty 'ParentNode'
$components | Sort-Object -Property 'Id'
Write-Host
$components | Sort-Object -Property 'Id' | Get-Unique

Если вы вставили в PowerShell, нажмите ввод после этой последней строки.

Вывод будет похож наthis:

PS C:\> $xmlDoc = [xml]@'
>> <root>
>>     <component Id='component1'>
>>         <regkey Id='regkey1'/>
>>     </component>
>>     <component Id='component2'>
>>         <file Id='file1' />
>>     </component>
>> </root>
>> '@
>>
PS C:\> $files = $xmlDoc.SelectNodes("//file[@Id='file1']")
PS C:\> $regkeys = $xmlDoc.SelectNodes("//regkey[@Id='regkey1']")
PS C:\> $components = $xmlDoc.SelectNodes("//component[@Id='component1'] | //component[@Id='component2
']")
PS C:\> $components += $regkeys | Select-Object -ExpandProperty 'ParentNode'
PS C:\> $components | Sort-Object -Property 'Id'

Id                                                 regkey
--                                                 ------
component1                                         regkey
component1                                         regkey
component2


PS C:\> Write-Host

PS C:\> $components | Sort-Object -Property 'Id' | Get-Unique

Id                                                 regkey
--                                                 ------
component1                                         regkey


PS C:\>

Обратите внимание, как component2 полностью исчезает, когда мы направляемся к Get-Unique.Может кто-нибудь объяснить это и предложить исправление, которое сохраняет схему запроса примерно такой же?

Редактировать : Я предполагал, что будет использоваться оператор -eq, чтобы увидеть, являются ли элементы ссылками натот же объект в памяти.Если я вручную попробую -eq, он покажет, что правильные объекты равны.Но Get-Unique, кажется, делает что-то еще.Если вы добавите этот код в конец приведенного выше сценария, он покажет эквивалентность объекта:

Write-Host
Write-Host "0: $($components[0].Id)"
Write-Host "1: $($components[1].Id)"
Write-Host "2: $($components[2].Id)"
Write-Host ("0 vs 1: " + ($components[0] -eq $components[1]))
Write-Host ("0 vs 2: " + ($components[0] -eq $components[2]))
Write-Host ("1 vs 2: " + ($components[1] -eq $components[2]))

Вывод (при запуске из файла сценария):

0: component1
1: component2
2: component1
0 vs 1: False
0 vs 2: True
1 vs 2: False

Ответы [ 2 ]

5 голосов
/ 14 сентября 2011

Вы можете использовать флаг -unique sort-object.Это дает ожидаемый результат для меня:

$components | Sort-Object -Property 'Id' -Unique
2 голосов
/ 14 сентября 2011

У меня такое ощущение, что Get-Unique хорошо работает для скалярных типов, таких как целые, строки и т. Д. (И, возможно, для набора общеизвестных типов), а не для общих объектов, потому что нет общего правила, определяющего объекты равны или нет.

Рассмотрим этот пример:

# getting unique string, works well
get-process | sort-object | select -expand processname | get-unique

# getting unique objects (PSObject), wrong result
get-process | sort-object | select -property processname | get-unique

# getting unique objects by their string representation, works well
get-process | sort-object | select -property processname | get-unique -asString

# what is the string representation?
[string](get-process | sort-object | select -property processname)[0]
#returns @{ProcessName=audiodg}

В вашем случае строковое представление:

[string]($components | Sort-Object -Property 'Id')[0]
# System.Xml.XmlElement

, поэтому даже -asString параметр не работает

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...