Как вычесть конкретное значение из свойства объекта? - PullRequest
0 голосов
/ 13 мая 2018

Допустим, у меня есть объект с именем $ data, который содержит следующее

  name    stock  
 ------- ------- 
  item1      10  
  item2      10  
  item3      10  

Как вычесть 1 стоимость товара item2?

Я пытался с этим:

$data.stock = $data.stock - 1 | Where-Object name -contains "item2"

Но я получаю следующую ошибку:

Method invocation failed because [System.Object[]] does not contain a method named 'op_Subtraction'.

Ответы [ 3 ]

0 голосов
/ 13 мая 2018

РЕДАКТИРОВАТЬ

Я могу только догадываться о структуре ваших данных, но похоже, что это массив.

Теперь я знаю, как создать переменную $data. Итак, это моя попытка:

$data = ConvertFrom-Csv -Header name, stock @'
item1,10
item2,10
item3,10
'@
$data | Format-Table -AutoSize
$data | Where-Object name -eq 'item2' | ForEach-Object { $_.stock -= 1 }
$data | Format-Table -AutoSize

Выход:

name  stock
----  -----
item1 10   
item2 10   
item3 10   

name  stock
----  -----
item1 10   
item2 9    
item3 10
0 голосов
/ 13 мая 2018

Полезный ответ Андрея Одегова предлагает PowerShell-идиоматическое решение, которое также демонстрирует упрощенный основанный на аргументах синтаксис Where-Object, называемый оператор сравнения , представленный в PSv3.

В PSv4 + есть еще один вариант, использующий * оператор '1008 *.Where() и .ForEach() коллекции методы , которые работают лучше;однако обратите внимание, что для этого требуется, чтобы входная коллекция находилась в памяти полностью [1] (что здесь имеет место):

 $data.Where({ $_.name -eq "Item2" }).ForEach({ $_.stock -= 1 })

Или, если вы знаете, что будет толькобыть one match, проще:

 $data.Where({ $_.name -eq "Item2" })[0].stock -= 1 

Также обратите внимание, как используется -eq вместо -contains, потому что $_.name является скаляром (одно значение), а не коллекция , а -contains предназначена для коллекций.


Что касается то, что вы пытались :

Похоже, вы пытались применить что-то похожее на понимание списка в стиле Python, которое PowerShell не поддерживает.

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

Я пробовал с этим:
$data.stock = $data.stock - 1 | Where-Object name -contains "item2"

В PSv3 +, доступ к свойству в коллекции возвращает массив ([System.Object[]]) значений свойств, собранных из элементов коллекции .

Следовательно, с вашими примерами данных $data.stock - 1 является эквивалентом:

(10, 10, 10) - 1  # !! BROKEN: arrays don't support the "-" operator

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


[1] Конвейер PowerShell и обработка всего в памяти :

Использование конвейера является относительно медленным, но ограничивает память, что позволяет обрабатывать коллекции, которые не помещаются в память в целом ;Например:

ConvertFrom-Csv in.csv | Where-Object ... | ForEach-Object ... | Export-Csv out.csv

В приведенном выше примере каждая строка из in.csv обрабатывается индивидуально и отправляется по конвейеру сразу , и Export-Csv создаетвывод строка за строкой .

Таким образом, нет необходимости считывать ввод в память в целом .

В отличие от этого,если выполнить обработку коллекции с помощью (с учетом массива) операторов / .Where()/.ForEach() методов / a foreach loop , вы получите более высокую производительность, но входные данные должны быть собраны в памяти полностью, заранее , что не всегда является опцией.

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

0 голосов
/ 13 мая 2018
$data = import-csv data.csv
$data

$data[1].stock -=1
$data

ForEach ($Row in $data){
  if ($Row.Name -eq 'item2') { $Row.stock -=1 }
}
$data

$data -match 'item2'|%{$_.stock -=1}

Пример вывода

name  stock
----  -----
item1 10
item2 10
item3 10

item1 10
item2 9
item3 10

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