Выберите значения свойств для всех объектов массива в PowerShell


допустим, у нас есть массив объектов $objects. Допустим, эти объекты имеют свойство "имя".

Это то, что я хочу сделать

 $results = @()
 $objects | %{ $results += $_.Name }

это работает, но можно ли это сделать лучше?

Если я делаю что-то вроде:

 $results = objects | select Name

$results - это массив объектов, имеющих свойство name. Я хочу, чтобы $results содержал массив имен.

есть ли лучший способ?

3 92

3 ответа:

Я думаю, вы могли бы использовать

как еще более простое решение, вы можете просто использовать:

$results = $objects.Name

, которые необходимо заполнить $results с массивом всех значений свойств 'Name' элементов в $objects.

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

  • за пределами трубопровода, использовать:

    $objects.Name
    (PSv3+), как показано в ответ rageandqq, что синтаксически проще и быстрее.

    • доступ к свойству в коллекциясравнительно медленно.

на маленький входные коллекции (массивы), вы, вероятно, не заметите разницы, и, особенно в командной строке, иногда возможность легко вводить команду более важна.


здесь простая в использовании альтернатива, который, однако, является самый медленный подход; он использует упрощенный ForEach-Object синтаксис называется операции заявлением (опять же, PSv3+): ; например, следующее решение PSv3+ легко добавить к существующей команде:

$objects | % Name      # short for: $objects | ForEach-Object -Process { $_.Name }

для полноты картины: малоизвестный PSv4+ .ForEach()метод сбора это еще одна альтернатива:

# By property name (string):
$objects.ForEach('Name')

# By script block (much slower):
$objects.ForEach({ $_.Name })
  • этот подход похож на член перечисление, С теми же компромиссами, за исключением того, что логика конвейера не применены; это чуть медленнее, хотя все еще заметно быстрее, чем трубопровод.

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

  • в script-block вариант, хотя и намного медленнее, позволяет произвольно преобразования; это более быстрая-all-In-memory-at - once-альтернатива конвейернойForEach-Object.


сравнение производительности различных подходов

здесь образец тайминги для различных подходов, основанных на входной коллекции 100,000 объекты, усредненные по 100 пробегам; абсолютные числа не важны и варьируются в зависимости от многих факторов, но это должно дать вам ощущение относительные производительность:

Command                                         FriendlySecs (100-run avg.) Factor
-------                                         --------------------------- ------
$objects.ForEach('Number')                      0.078                       1.00
$objects.Number                                 0.079                       1.02
foreach($o in $objects) { $o.Number }           0.188                       2.42
$objects | Select-Object -ExpandProperty Number 0.881                       11.36
$objects.ForEach({ $_.Number })                 0.925                       11.93
$objects | % { $_.Number }                      1.564                       20.16
$objects | % Number                             2.974                       38.35
  • решение метода сбора на основе перечисления элементов / свойств на основе имен выполняется быстрее в 10 раз, чем самое быстрое решение на основе конвейера.

  • The foreachсообщении решение о 2.5 медленнее, но все же примерно в 4-5 раз быстрее, чем самое быстрое решение трубопровода.

  • использование блок скрипта С решением метода сбора (.ForEach({ ... }) резко замедляет работу, так что он практически на одном уровне с самым быстрым решением на основе конвейера (Select-Object -ExpandProperty).

  • % Number (ForEach-Object Number), что любопытно, выполняет хуже всего, хотя % Number является концептуальным эквивалентом % { $_.Number }).


исходный код для тестов:

Примечание: функция загрузки Time-Command С в этом суть для выполнения этих тестов.

$count = 1e5 # input-object count (100,000)
$runs  = 100  # number of runs to average 

# Create sample input objects.
$objects = 1..$count | % { [pscustomobject] @{ Number = $_ } }

# An array of script blocks with the various approaches.
$approaches = { $objects | Select-Object -ExpandProperty Number },
              { $objects | % Number },
              { $objects | % { $_.Number } },
              { $objects.ForEach('Number') },
              { $objects.ForEach({ $_.Number }) },
              { $objects.Number },
              { foreach($o in $objects) { $o.Number } }

# Time the approaches and sort them by execution time (fastest first):
Time-Command $approaches -Count $runs | Select Command, FriendlySecs*, Factor