javascript array.splice(index, howmany, item1, ....., itemX)
index Required. The position to add/remove items. Negative value defines the position from the end of the array.
howmany Optional. Number of items to be removed.
item1, ..., itemX Optional. New elements(s) to be added.
Now, I want to get this same functionality in Powershell:
function splice {
param(
[string[]]$Array,
[int32]$Index,
[int32]$HowMany,
[string[]]$Item
)
}
$lines = @(
"abc",
"xyz"
"123"
)
$lines = splice -Array $lines -Index 1 -HowMany 0 -Item "foo", "bar"
Maybe there's a better way?
CodePudding user response:
Here's a naive implementation with no error handling, and probably a terrible performance profile...
function splice
{
param
(
[string[]] $Array,
[int32] $Index,
[int32] $HowMany,
[string[]] $Item
)
foreach( $x in ($Array | select-object -First $Index) )
{
write-output $x
}
foreach( $x in $Item )
{
write-output $x
}
foreach( $x in ($Array | select-object -Skip ($Index $HowMany)) )
{
write-output $x
}
}
Examples with test data taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
$months = @( "Jan", "March", "April", "June" );
splice $months 1 0 "Feb";
# inserts at index 1
# expected output: Array ["Jan", "Feb", "March", "April", "June"]
$months = @( "Jan", "Feb", "March", "April", "June" );
splice $months 4 1 "May";
# replaces 1 element at index 4
# expected output: Array ["Jan", "Feb", "March", "April", "May"]
Note that it doesn't mutate the existing array in place though, but you can simulate that by assigning the result back to the variable - e.g.:
$months = @( "Jan", "March", "April", "June" );
$months = splice $months 1 0 "Feb";
There's probably some nicer things you can do with the ValueFromPipeline
parameter attribute to allow you to pipe a variable in, but it's well past my bedtime here...
CodePudding user response:
I was thinking more of using an ArrayList, because that already has methods RemoveRange()
and InsertRange()
:
function splice {
param (
[Parameter(Mandatory = $true, Position = 0)]
[string[]]$Array,
[Parameter(Mandatory = $true, Position = 1)]
[int32]$Index,
[Parameter(Mandatory = $false, Position = 2)]
[int32]$HowMany = 0,
[Parameter(Mandatory = $false, Position = 3)]
[string[]]$Item = $null
)
# convert negative index to positive
$idx = if ($Index -lt 0) { $Array.Count $Index } else { $Index }
if ($idx -lt 0 -or $idx -ge $Array.Count) {
Write-Error "Index $Index out of range"
return
}
# initialize an ArrayList with all values from $Array
# an ArrayList can hold elements of any type
$aList = [System.Collections.ArrayList]::new($Array)
# In this case, since you are using [string[]] to typecast the parameters for $Array and $Item, you could also use
# $aList = [System.Collections.Generic.List[string]]::new($Array)
# do we need to remove items?
if ($HowMany -ge 0) {
$aList.RemoveRange($idx, [math]::Min($HowMany, $aList.Count - $idx))
}
# do we need to insert/append new items?
if ($Item.Count) {
$aList.InsertRange($idx, $Item)
}
# return as array. use unary comma to ensure the function returns an array
# even if there is only one element left
,$alist.ToArray()
}
Some tests:
$test = 'abc', 'def', 'xyz', '123'
splice $test -1 5 'add this','and this one too' # remove last item '123' and append two new items
splice $test 2 1 'add this','and this one too' # remove third item 'xyz' and insert two new items
splice $test 3 0 'add this','and this one too' # insert two new items before fourth element '123'
splice $test 4 2 'add this','and this one too' # error 'splice : Index 4 out of range'