问题
I'm struggling a bit to remove the first line (item ID) of an array.
$test.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
To list all the options I tried ,$test | gm
and it clearly states:
Remove Method void IList.Remove(System.Object value)
RemoveAt Method void IList.RemoveAt(int index)
So when I try $test.RemoveAt(0)
I get the error:
Exception calling "RemoveAt" with "1" argument(s): "Collection was of a fixed size."At line:1 char:1
+ $test.RemoveAt(1)
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : NotSupportedException
So I finally found here that my array needs to be of the type System.Object
to be able to use $test.RemoveAt(0)
. Is it best practice to declare all the arrays in the beginning of the script as a list? Or is it better to convert the arrays with $collection = ({$test}.Invoke())
to a list later on when this functionality is needed?
What are the pro's and cons of both types? Thank you for your help.
回答1:
An alternative option is to use Powershell's ability to assign multiple variables (see this other answer).
$arr = 1..5
$first, $rest= $arr
$rest
2
3
4
5
It's been a feature of Powershell for over a decade. I found this functionality from an MSDN blog post:
回答2:
Arrays are fixed-size, like the error says. RemoveAt()
is an inherited method that doesn't apply to normal arrays. To remove the first entry in the array, you could overwrite the array by a copy that includes every item except the first, like this:
$arr = 1..5
$arr
1
2
3
4
5
$arr = $arr[1..($arr.Length-1)]
$arr
2
3
4
5
If you need to remove values at different indexes then you should consider using a List
. It supports Add()
, Remove()
and RemoveAt()
:
#If you only have a specific type of objects, like int, string etc. then you should edit `[System.Object] to [System.String], [int] etc.
$list = [System.Collections.Generic.List[System.Object]](1..5)
$list
1
2
3
4
5
$list.RemoveAt(0)
$list
2
3
4
5
See my earlier SO answer and about_Arrays for more details about how arrays work.
回答3:
This will allow you to remove every occurrence of an arbitrary element from an array without resorting to a more sophisticated .NET object.
$x=<array element to remove>
$test = $test | Where-Object { $_ -ne $test[$x] }
This will do the same, but will only remove one of the elements. If there are duplicates, they will remain.
$x=<array element to remove>
$skip=$true
$test = $test | ForEach-Object { if (($_ -eq $x) -and $skip) { $skip=$false } else { $_ } }
回答4:
You can use Select-Object -Skip <count> to omit the first count item(s):
PS C:\> 1..3 | Select-Object -Skip 1
2
3
PS C:\>
PS C:\> 1 | Select-Object -Skip 1
PS C:\>
回答5:
Just to update - there's an issue with @Frode F. answer
If the number of elements in array is more than 1
$arr = $arr[1..($arr.Length-1)]
If the number of elements is 1, then this doesn't remove the element
if($arr.Length -le 1) {
$arr = @()
}
else {
$arr = $arr[1..($arr.length - 1)]
}
回答6:
I think it's going to depend on the circumstances. If you only need to remove that first element once, then you can use array slicing:
$arr = $arr[1..($arr.length-1)]
If you're going to do it repeatedly, then you should start with an arraylist or generic collection. If it's a large array, you might want to just put the expression that's creating it into a scriptblock and do an .invoke() on that rather than letting the pipeline create an array and then convert that to a collection.
回答7:
Excuse the late answer, but I was struggling with this also. For my intents and purposes (writing to a text file), I realized that since the array was a fixed size -- instead of removing it I could just set the value to string.empty.
$results = SQLQuery -connectionString $connectionString -query $query;
$results[0] = '';
foreach ($r in $results) {
Add-Content $skus $r[0];
}
For me this got rid of the header that I didn't want in my flat file. Hope this helps someone else out there.
回答8:
If we have the case when big array(or ArrayList) must be performed by some parts - I used some lifehack:
#$bigArray with thousands of items
while($bigArray.Count -gt 0)
{
if($bigArray.Count -gt 100)
{
$k = 100
}else {$k = $bigArray.Count}
$part = $bigArray | select -First $k
#now we can make some operations with this $part
#in the end of loop we should exclude this part from big array
if($bigArray.Count -gt 100)
{
$bigArray = $bigArray | select -Last ($bigArray.Count - $k)
}else {$bigArray = @()}#in this step we have been handle last part of array and we should null him for stop loop
}
And now we can handle big array by some parts(by 100 items)
回答9:
removeat() works with arraylists (like $error):
[collections.arraylist]$a = get-process
$a.removeat(0)
来源:https://stackoverflow.com/questions/24754822/powershell-remove-item-0-from-an-array