2014-07-15 17 views
9

Trochę walczę o usunięcie pierwszego wiersza (identyfikator przedmiotu) z tablicy.PowerShell Usuń element [0] z tablicy

$test.GetType() 

IsPublic IsSerial Name          BaseType                          
-------- -------- ----          --------                          
True  True  Object[]         System.Array 

Aby wyświetlić wszystkie opcje próbowałem ,$test | gm i wyraźnie stwierdza:

Remove   Method    void IList.Remove(System.Object value)                        
RemoveAt  Method    void IList.RemoveAt(int index) 

Więc gdy próbuję $test.RemoveAt(0) pojawia się błąd:

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 

Więc w końcu znalazłem here że moja tablica musi być typu System.Object, aby móc używać $test.RemoveAt(0). Czy najlepiej jest deklarować wszystkie tablice na początku skryptu jako listę? A może lepiej przekształcić tablice z $collection = ({$test}.Invoke()) na listę później, kiedy ta funkcja jest potrzebna?

Jakie są typy i wady obu typów? Dziękuję za pomoc.

Odpowiedz

15

Tablice mają stały rozmiar, tak jak mówi błąd. RemoveAt() jest dziedziczoną metodą, która nie ma zastosowania do zwykłych tablic. Aby usunąć pierwszy wpis w tablicy, można zastąpić tablicę z kopią, która obejmuje każdy element z wyjątkiem pierwszego, na przykład:

$arr = 1..5 

$arr 
1 
2 
3 
4 
5 

$arr = $arr[1..($arr.Length-1)] 

$arr 
2 
3 
4 
5 

Jeśli trzeba usunąć wartości w różnych indeksów wówczas należy rozważyć użycie List. Obsługuje Add(), Remove() i 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 

zobaczyć moje wcześniejsze SO answer i about_Arrays uzyskać więcej informacji dotyczących sposobu pracy tablic.

1

Myślę, że to zależy od okoliczności. Jeśli trzeba tylko usunąć ten pierwszy element raz, a następnie można użyć tablicy krojenie:

$arr = $arr[1..($arr.length-1)] 

Jeśli masz zamiar to zrobić wielokrotnie, to należy zacząć od ArrayList lub kolekcji generycznych. Jeśli jest to duża tablica, możesz po prostu umieścić wyrażenie tworzące ją w bloku skryptów i wykonać na niej polecenie .invoke(), zamiast pozwolić potokowi utworzyć tablicę, a następnie przekonwertować ją do kolekcji.

0

Przepraszam za późną odpowiedź, ale ja też zmagałem się z tym. Dla moich zamiarów i celów (pisanie do pliku tekstowego) zdałem sobie sprawę, że ponieważ tablica ma stały rozmiar - zamiast go usunąć, mogę ustawić wartość na string.empty.

$results = SQLQuery -connectionString $connectionString -query $query; 
$results[0] = ''; 
foreach ($r in $results) { 
    Add-Content $skus $r[0]; 
} 

Dla mnie to pozbyło się nagłówka, którego nie chciałem w moim płaskim pliku. Mam nadzieję, że to pomoże komuś innemu.

2

Wystarczy zaktualizować - nie ma problemu z @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)] 
} 
7

Pozwoli to usunąć wszystkie wystąpienia dowolnego elementu z tablicy bez uciekania się do bardziej wyrafinowane Obiekt .NET.

$x=<array element to remove> 
$test = $test | Where-Object { $_ -ne $test[$x] } 

Wykona to samo, ale usunie tylko jeden z elementów. Jeśli są duplikaty, pozostaną.

$x=<array element to remove> 
$skip=$true 
$test = $test | ForEach-Object { if (($_ -eq $x) -and $skip) { $skip=$false } else { $_ } } 
+0

Przegłosowano, to mi się udało. I jest ładne i zwięzłe. – Spikee

+0

Może zachowywać się niepoprawnie, jeśli tablica zawiera zduplikowane wartości. –

+0

@RonMacNeil, dobry punkt. Zaktualizowałem swoją odpowiedź. –