Reputation: 111
I have a pretty basic PowerShell array: $TestArray with 2 text columns: Price and TimeStamp (that's the way I get them, nothing to be done about this):
Price TimeStamp
----- ----------------
0.0567 1542056680.72746
0.0567 1542056650.34414
0.0555 1542056197.46668
0.0551 1542056167.28967
I would like, in a single PowerShell line to add a rounded Time2
value
$Time2 = [math]::Round($TestArray.TimeStamp)
The code I am thinking of is:
$TestArray | Add-Member -Name Time2 -MemberType NoteProperty -Value { [math]::Round($Table.TimeStamp) }
Of course, I can do a ForEach loop; it would take care of it easily, but I would like to achieve this in this single line of code.
Any idea ?
Cheers, Philippe
Upvotes: 3
Views: 689
Reputation: 440637
Mathias R. Jessen's answer directly solves your problem, by creating a script property (type ScriptProperty
) that dynamically calculates its value from the enclosing object's .TimeStamp
property.
.TimeStamp
will correctly be reflected in .Time2
, albeit at the cost of having to calculate the value on every access.Manuel Batsching's answer offers a Select-Object
-based alternative that creates static note properties (type NoteProperty
), as you've originally attempted yourself.
.TimeStamp
won't be reflected in .Time2
.To offer faster PSv5+ alternatives (a single method call each, spread across multiple lines for readability):
# ScriptProperty - dynamic
$TestArray.ForEach({
$_.psobject.properties.Add(
[psscriptproperty]::new('Time2', { [math]::Round($this.TimeStamp) })
)
})
# NoteProperty - static
$TestArray.ForEach({
$_.psobject.properties.Add(
[psnoteproperty]::new('Time2', [math]::Round($_.TimeStamp))
)
})
The above solutions use the PSv4+ .ForEach()
collection method and the PSv5+ static ::new()
type method for calling constructors.
Finally, re one-liner:
The following foreach
-loop based note-property solution would have solved your problem too, and would have been faster; while it is spread across multiple lines for readability here, it also works as a one-liner:
foreach ($el in $TestArray) {
Add-Member -InputObject $el -Name Time2 -MemberType NoteProperty `
-Value ([math]::Round($el.TimeStamp))
}
Generally, while the pipeline often enables more elegant, single-command solution, that - unfortunately - comes at the expense of performance.
Upvotes: 5
Reputation: 3616
Alternatively you can achieve the same with Select-Object
and a custom property:
$TestArray | Select-Object *,@{ n='Time2';e={ [math]::Round($_.TimeStamp) }}
Upvotes: 2
Reputation: 175084
Change the member type to ScriptProperty
and refer to the individual array item as $this
:
$TestArray |Add-Member Time2 -Value { [math]::Round($this.Timestamp) } -MemberType ScriptProperty
Worth noting that in this example, the pipeline itself acts as a foreach
loop, unravelling the array and binding each individual item to Add-Member
Upvotes: 1