Зачем мне использовать упорядоченный хэш в PowerShell? - PullRequest
0 голосов
/ 18 октября 2018

Я прочитал учебник и узнал, что PowerShell поддерживает упорядоченные хэши.Когда я буду использовать эту функцию?

Пример того, о чем я говорю:

$hash = [ordered]@{ ID = 1; Shape = "Square"; Color = "Blue"}

Ответы [ 2 ]

0 голосов
/ 18 октября 2018

Позвольте мне дополнить Полезный ответ TheIncorrigible1 с более широкой перспективой:

tl; др

  • Большую часть времени вы хотите [ordered] @{ ... } ([System.Collections.Specialized.OrderedDictionary]) (PSv3 +):

    • Он обеспечивает перечисление записей в том порядке, в которомони были определены (также отражено в свойствах коллекции .Keys и .Values).
    • Он также позволяет получить доступ к записям по index , как к массиву.
  • Как правило, вы можете использовать [ordered] @{ ... } взаимозаменяемо с @{ ... }, обычной хеш-таблицей, [hashtable] aka [System.Collections.Hashtable], потому что оба типа реализуют [IDictionary] interface , как обычно набираются параметры, принимающие хеш-таблицы.

Потеря производительности, которую вы платите за использование [ordered], ничтожна.


Немного предыстории:

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

Это хорошо для случаев использования, когда все, что вы делаете, это выполняете изолированный поиск по ключу, где упорядочение среди ключей (записей) не имеет значения.

Однако, часто вы заботитесь о порядке записей:

  • в простейшем случае для отображения целей;что-то смущает, когда видят порядок определений;например:

    @{ one = 1; two = 2; three = 3 } 
    
    Name                           Value
    ----                           -----
    one                            1
    three                          3   # !! 
    two                            2
    
  • , что более важно, перечисление записей может быть предсказуемым для дальнейшей программной обработки;например (примечание: строго говоря, порядок свойств не имеет значения в JSON, но он снова важен для наблюдателя):

    # No guaranteed property order.
    PS> @{ one = 1; two = 2; three = 3 } | ConvertTo-Json
    {
     "one": 1,
     "three": 3, # !!
     "two": 2
    }
    
    # Guaranteed property order.
    PS> [ordered] @{ one = 1; two = 2; three = 3 } | ConvertTo-Json
    {
      "one": 1,
      "two": 2,
      "three": 3
    }
    

К сожалению, хеш-таблица PowerShell-литеральный синтаксис, @{ ... }, не по умолчанию [ordered] [1] , но уже слишком поздно это менять.

Существует один контекст, в котором [ordered] подразумевается подразумевается , однако: если вы приведете хеш-таблицу литерал к [pscustomobject] для создания пользовательского объекта:

[pscustomobject] @{ ... } - синтаксический сахар для [pscustomobject] [ordered] @{ ... };то есть свойства результирующего пользовательского объекта упорядочиваются на основе порядка ввода в литерале хеш-таблицы;например:

PS> [pscustomobject] @{ one = 1; two = 2; three = 3 }

one two three  # order preserved!
--- --- -----
  1   2     3

Обратите внимание, однако, что этот работает только в точности так, как показано выше: если приведение применяется напрямую к хеш-таблице литерал ;если вы используете переменную , чтобы сначала сохранить хеш-таблицу, или если вы просто заключили литерал в (...), порядок будет потерян:

PS> $ht = @{ one = 1; two = 2; three = 3 }; [pscustomobject] $ht

one three two  # !! Order not preserved.
--- ----- ---
  1     3   2


PS> [pscustomobject] (@{ one = 1; two = 2; three = 3 }) # Note the (...)

one three two  # !! Order not preserved.
--- ----- ---
  1     3   2

Следовательно, если высначала создайте хеш-таблицу , а затем , а затем приведите ее к [pscustomobject], вы должны начать с [ordered] хеш-таблицы , чтобы получить предсказуемое упорядочение свойств;этот метод полезен, потому что проще создавать записи хеш-таблицы, чем добавлять свойства к пользовательскому объекту;Например:

$oht = [ordered] @{} # Start with an empty *ordered* hashtable 
# Add entries iteratively.
$i = 0
foreach ($name in 'one', 'two', 'three') {
  $oht[$name] = ++$i
}
[pscustomobject] $oht # Convert the ordered hashtable to a custom object

Наконец, обратите внимание, что [ordered] может применяться только к хеш-таблице literal ;Вы не можете использовать его для преобразования ранее существовавшей обычной хеш-таблицы в упорядоченную (что в любом случае не имело бы никакого смысла, поскольку у вас нет определенного порядка для начала):

PS> $ht = @{ one = 1; two = 2; three = 3 }; [ordered] $ht # !! Error
...
The ordered attribute can be specified only on a hash literal node.
...

На заметку: Ни упорядоченные, ни обычные хеш-таблицы не перечисляют свои записи при отправке через конвейер ;они отправляются целиком.
Чтобы перечислить записи, используйте метод .GetEnumerator() ;Например:

@{ one = 1; two = 2; three = 3 }.GetEnumerator() | ForEach-Object { $_.Value }
1
3  # !!
2

Что касается влияния на производительность при использовании [ordered]:

Как отмечалось, оно незначительно ;Вот некоторые примеры времени, усредненные по 10000 прогонов, с использованием Time-Command:

Time-Command -Count 10,000 { $ht=@{one=1;two=2;three=3;four=4;five=5;six=6;seven=7;eight=8;nine=9}; foreach($k in $ht.Keys){$ht.$k} }, 
                           { $ht=[ordered] @{one=1;two=2;three=3;four=4;five=5;six=6;seven=7;eight=8;nine=9}; foreach($k in $ht.Keys){$ht.$k} }

Примеры времени (Windows PowerShell 5.1 в Windows 10, одноядерная виртуальная машина):

Command                 TimeSpan         Factor
-------                 --------         ------
$ht=@{one=1;two=2;th... 00:00:00.0000501 1.00  
$ht=[ordered] @{one=... 00:00:00.0000527 1.05  

То есть [ordered] составило всего 5% замедления.


[1] Incorrigible1 указывает на один хитрый аспект, характерный для [ordered] хеш-таблиц :

с числовыми клавишами , различая между key и index могут стать хитрыми;, чтобы принудительно интерпретировать число как ключ , приведите его к [object]:

# Ordered hashtable with numeric keys.
PS> $oht = [ordered] @{ 1 = 'one'; 2 = 'two' }

PS> $oht[1]  # same as $oht.1 - interpreted as *index* -> 2nd entry
two

PS> $oht[[object] 1] # interpreted as *key* -> 1st entry.
one

Тем не менее, цифровые клавиши не являются общими имне преимущество от использования предсказуемого перечисления перевешивает эту незначительную проблему.

Тип платформы .NET, лежащий в основе [ordered], System.Collections.Specialized.OrderedDictionary, был доступен начиная с v1, поэтому PowerShell мог бы выбрать его в качестве реализации по умолчанию для@{ ... } с самого начала, даже в PowerShell v1.
Учитывая приверженность PowerShell к обратной совместимости, изменение значения по умолчанию больше не вариант, поскольку это может нарушить существующий код.

0 голосов
/ 18 октября 2018

Причиной использования словаря ordered является отображение / типизация.Например, если вы хотите преобразовать hashtable в PSCustomObject и хотите, чтобы ваши ключи были в том порядке, в котором вы их вводите, вы используете ordered.

.здесь используется случай, когда вы используете Export-Csv, заголовки в правильном порядке.Это всего лишь один пример, который я мог придумать с головы до головы.По типу тип hashtable не заботится о порядке ввода ключей / значений и будет отличаться при каждом отображении его в потоке успеха.

Дополнительный вариант использования для orderedсловарь: вы можете рассматривать вашу хеш-таблицу как массив и использовать числовые методы доступа для поиска элементов, например $myOrderedHash[-1] будет захватывать последний элемент, добавленный в словарь.

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