Verwenden Sie System.Collections.ObjectModel.Collection<Foo>.
Abatishchev
1
Für mein Spiel habe ich eine "null at index" -Datenstruktur verwendet. Grundsätzlich hat das innere Array (Puffer) eine statische Größe, und anstatt den Index zu entfernen und die Größe des Arrays zu ändern, mache ich den Index einfach null. Wenn ich ein Element hinzufügen muss, finde ich einfach den ersten Nicht-Null-Index und platziere ihn dort. Funktioniert ziemlich gut, aber offensichtlich nicht für alles.
Krythic
Antworten:
202
Wenn Sie List nicht verwenden möchten:
var foos =newList<Foo>(array);
foos.RemoveAt(index);return foos.ToArray();
Sie können diese Erweiterungsmethode ausprobieren, die ich noch nicht getestet habe:
publicstatic T[]RemoveAt<T>(this T[] source,int index){
T[] dest =new T[source.Length-1];if( index >0)Array.Copy(source,0, dest,0, index);if( index < source.Length-1)Array.Copy(source, index +1, dest, index, source.Length- index -1);return dest;}
Das erste Beispiel in dieser Antwort ist viel weniger effizient als das zweite. Es erfordert zwei Array-Kopien und eine Verschiebung von allem nach dem Index anstelle einer selektiven Array-Kopie.
Martin Brown
2
+1 natürlich, aber wir können auch list verwenden ODER List <Foo> list = new List <Foll> (GetFoos ()); list.Remove (my_foo); list.RemoveAt (2); wo GetFoos () das Array von Foos zurückgibt !!!!
Shahjapan
2
In der ersten Zeile der Methode sollte "source.Length" anstelle von "array.Length" stehen.
Nelson
1
Beachten Sie außerdem, dass jede Variable, die einen Verweis auf das ursprüngliche Array speichert, weiterhin die ursprünglichen Daten enthält und dass jeder Vergleich der Referenzgleichheit zwischen dem Array in der Quelle und dem Ausgabearray ein Negativ zurückgibt.
bkqc
1
@MartinBrown Tatsächlich ist das Konvertieren einer Liste in \ from und Array viel langsamer als eine Array-Kopie (die die Daten mit nur wenigen ASM-Anweisungen mit der von der CPU zulässigen Höchstgeschwindigkeit kopieren kann). Außerdem ist das Verschieben einer Liste sehr schnell, da nur einige Zeiger ausgetauscht und die Knotendaten entfernt werden müssen (in diesem Fall nur 8 Byte [plus weitere 16 für die Head \ Tail-Zeiger]).
Krowe2
66
Die Natur von Arrays ist, dass ihre Länge unveränderlich ist. Sie können keine Array-Elemente hinzufügen oder löschen.
Sie müssen ein neues Array erstellen, das ein Element kürzer ist, und die alten Elemente in das neue Array kopieren, mit Ausnahme des Elements, das Sie löschen möchten.
Daher ist es wahrscheinlich besser, eine Liste anstelle eines Arrays zu verwenden.
Konvertieren Sie das Array in eine ListeList<mydatatype> array = new List<mydatatype>(arrayofmydatatype)
Immortal Blue
1
@ImmortalBlue oder einfach var myList = myArray.ToList();mit der Enumerable.ToList()Methode aus dem System.LinqNamespace.
Dyndrilliac
58
Ich benutze diese Methode, um ein Element aus einem Objektarray zu entfernen. In meiner Situation sind meine Arrays klein. Wenn Sie also große Arrays haben, benötigen Sie möglicherweise eine andere Lösung.
Ich persönlich mag diese Antwort besser als die akzeptierte Antwort. Es sollte genauso effizient sein und es ist viel einfacher zu lesen. Ich kann es mir ansehen und weiß, dass es richtig ist. Ich müsste den anderen testen, um sicherzustellen, dass diese Kopien korrekt geschrieben wurden.
Oillio
1
Es ist wirklich eine Schande, dass diese Antwort so niedrig ist, wenn sie bei weitem besser ist als die beiden darüber.
Sepulchritude
Aaarhg, das ist die Antwort, nach der ich gesucht habe! Dies ist die beste Methode ohne Listen.
Jordi Huertas
47
Einzeilige LINQ-Lösung:
myArray = myArray.Where((source, index)=> index !=1).ToArray();
Das 1in diesem Beispiel ist der Index des zu entfernenden Elements - in diesem Beispiel gemäß der ursprünglichen Frage das zweite Element (wobei 1es das zweite Element bei der C # -Null-basierten Array-Indizierung ist).
Für Bereiche, die einen leistungsstarken / häufigen Zugriff erfordern, wird LINQ nicht empfohlen.
Krythic
3
@ Krythic Das ist ein fairer Kommentar. Die Leistung dieser Lösung wird tausende Male in einer engen Schleife ausgeführt und ist nicht so gut wie bei einigen anderen hoch bewerteten
Jon Schneider
9
Auf diese Weise können Sie ein Array-Element ab .Net 3.5 löschen, ohne es in ein anderes Array zu kopieren. Verwenden Sie dazu dieselbe Array-Instanz mit Array.Resize<T>:
publicstaticvoidRemoveAt<T>(ref T[] arr,int index){for(int a = index; a < arr.Length-1; a++){// moving elements downwards, to fill the gap at [index]
arr[a]= arr[a +1];}// finally, let's decrement Array's size by oneArray.Resize(ref arr, arr.Length-1);}
„ohne auf ein anderes Array zu Kopieren“ - pro verknüpften Dokumentation, Array.Resize tatsächlich tut ein neues Array hinter den Kulissen zuweisen, und kopiert die Elemente aus dem alten Array in den neuen. Trotzdem gefällt mir die Prägnanz dieser Lösung.
Jon Schneider
Sehr schön und klar, wenn Sie sicher sind, dass es sich um ein relativ kleines Array handelt.
Darren
1
Wenn Sie den Kommentar von @ JonSchneider fortsetzen, handelt es sich nicht um "dieselbe Array-Instanz". Aus diesem Grund müssen Sie refbeim Aufrufen der ResizeMethode verwenden. Die Länge einer Array-Instanz ist fest und unveränderlich.
Jeppe Stig Nielsen
2
Wenn die Reihenfolge der Elemente nicht wichtig ist, können Sie das Element am Index gegen das letzte Element austauschen und dann die Größe ändern, anstatt alle Elemente nach unten zu verschieben: arr [index] = arr [arr.Length - 1]; Array.Resize (ref arr, arr.Length - 1);
Bartel
5
Hier ist eine alte Version, die auf Version 1.0 des .NET Frameworks funktioniert und keine generischen Typen benötigt.
publicstaticArrayRemoveAt(Array source,int index){if(source ==null)thrownewArgumentNullException("source");if(0> index || index >= source.Length)thrownewArgumentOutOfRangeException("index", index,"index is outside the bounds of source array");Array dest =Array.CreateInstance(source.GetType().GetElementType(), source.Length-1);Array.Copy(source,0, dest,0, index);Array.Copy(source, index +1, dest, index, source.Length- index -1);return dest;}
Dies wird folgendermaßen verwendet:
classProgram{staticvoidMain(string[] args){string[] x =newstring[20];for(int i =0; i < x.Length; i++)
x[i]=(i+1).ToString();string[] y =(string[])MyArrayFunctions.RemoveAt(x,3);for(int i =0; i < y.Length; i++)Console.WriteLine(y[i]);}}
So habe ich es für mein Spiel gemacht. Verwenden Sie nullfähige Puffer für Bereiche, die sehr häufig geändert werden.
Krythic
2
Wie immer bin ich zu spät zur Party ...
Ich möchte der bereits vorhandenen Liste der netten Lösungen eine weitere Option hinzufügen. =)
Ich würde dies als eine gute Gelegenheit für Erweiterungen sehen.
publicstaticElementDefinitionImpl[]RemoveElementDefAt(ElementDefinition[] oldList,int removeIndex
){ElementDefinitionImpl[] newElementDefList =newElementDefinitionImpl[ oldList.Length-1];int offset =0;for(int index =0; index < oldList.Length; index++){ElementDefinitionImpl elementDef = oldList[ index ]asElementDefinitionImpl;if( index == removeIndex ){// This is the one we want to remove, so we won't copy it. But // every subsequent elementDef will by shifted down by one.
offset =-1;}else{
newElementDefList[ index + offset ]= elementDef;}}return newElementDefList;}
In einem normalen Array müssen Sie alle Array-Einträge über 2 mischen und dann die Größe mithilfe der Resize-Methode ändern. Möglicherweise ist es besser, eine ArrayList zu verwenden.
Hier ist eine kleine Sammlung von Hilfsmethoden, die ich basierend auf einigen der vorhandenen Antworten erstellt habe. Es verwendet sowohl Erweiterungen als auch statische Methoden mit Referenzparametern für maximale Idealität:
publicstaticclassArr{publicstaticintIndexOf<TElement>(thisTElement[]Source,TElementElement){for(var i =0; i <Source.Length; i++){if(Source[i].Equals(Element))return i;}return-1;}publicstaticTElement[]Add<TElement>(refTElement[]Source,paramsTElement[]Elements){varOldLength=Source.Length;Array.Resize(refSource,OldLength+Elements.Length);for(int j =0,Count=Elements.Length; j <Count; j++)Source[OldLength+ j]=Elements[j];returnSource;}publicstaticTElement[]New<TElement>(paramsTElement[]Elements){returnElements??newTElement[0];}publicstaticvoidRemove<TElement>(refTElement[]Source,paramsTElement[]Elements){foreach(var i inElements)RemoveAt(refSource,Source.IndexOf(i));}publicstaticvoidRemoveAt<TElement>(refTElement[]Source,intIndex){varResult=newTElement[Source.Length-1];if(Index>0)Array.Copy(Source,0,Result,0,Index);if(Index<Source.Length-1)Array.Copy(Source,Index+1,Result,Index,Source.Length-Index-1);Source=Result;}}
In Bezug auf die Leistung ist es anständig, aber es könnte wahrscheinlich verbessert werden. Removeverlässt sich darauf IndexOfund für jedes Element, das Sie durch Aufrufen entfernen möchten, wird ein neues Array erstellt RemoveAt.
IndexOfist die einzige Erweiterungsmethode, da das ursprüngliche Array nicht zurückgegeben werden muss. Newakzeptiert mehrere Elemente eines Typs, um ein neues Array dieses Typs zu erzeugen. Alle anderen Methoden müssen das ursprüngliche Array als Referenz akzeptieren, sodass das Ergebnis nicht später zugewiesen werden muss, da dies bereits intern geschieht.
Ich hätte eine MergeMethode zum Zusammenführen von zwei Arrays definiert. Dies kann jedoch bereits mit der AddMethode erreicht werden, indem ein tatsächliches Array gegenüber mehreren einzelnen Elementen übergeben wird. Daher Addkann auf zwei Arten verwendet werden, um zwei Sätze von Elementen zu verbinden:
Ich weiß, dass dieser Artikel zehn Jahre alt und daher wahrscheinlich tot ist, aber ich würde Folgendes versuchen:
Verwenden Sie die IEnumerable.Skip () -Methode in System.Linq . Das ausgewählte Element wird aus dem Array übersprungen und eine weitere Kopie des Arrays zurückgegeben, die nur alles außer dem ausgewählten Objekt enthält. Wiederholen Sie dies dann einfach für jedes Element, das Sie entfernen möchten, und speichern Sie es anschließend in einer Variablen.
Zum Beispiel, wenn wir ein Array mit dem Namen "Sample" (vom Typ int []) mit 5 Zahlen haben. Wir wollen den zweiten entfernen und versuchen "Sample.Skip (2);" sollte das gleiche Array zurückgeben, außer ohne die 2. Nummer.
Umgeht diese Methode nicht einfach eine bestimmte Anzahl von Elementen in einer Sequenz und gibt dann die verbleibenden Elemente zurück ? In Ihrem Beispiel "überspringen" Sie die ersten beiden Elemente der generischen Liste und nicht nur das zweite!
xnr_z
-4
Erster Schritt
Sie müssen das Array in eine Liste konvertieren. Sie können eine Erweiterungsmethode wie diese schreiben
// Convert An array of string to a list of stringpublicstaticList<string>ConnvertArrayToList(thisstring[]array){// DECLARE a list of string and add all element of the array into itList<string> myList =newList<string>();foreach(string s inarray){
myList.Add(s);}return myList;}
Zweiter Schritt
Schreiben Sie eine Erweiterungsmethode, um die Liste wieder in ein Array zu konvertieren
// convert a list of string to an array publicstaticstring[]ConvertListToArray(thisList<string>list){string[]array=newstring[list.Capacity];array=list.Select(i => i.ToString()).ToArray();returnarray;}
Letzte Schritte
Schreiben Sie Ihre endgültige Methode, aber denken Sie daran, das Element am Index zu entfernen, bevor Sie es wieder in ein Array wie den Code show konvertieren
System.Collections.ObjectModel.Collection<Foo>
.Antworten:
Wenn Sie List nicht verwenden möchten:
Sie können diese Erweiterungsmethode ausprobieren, die ich noch nicht getestet habe:
Und benutze es wie:
quelle
Die Natur von Arrays ist, dass ihre Länge unveränderlich ist. Sie können keine Array-Elemente hinzufügen oder löschen.
Sie müssen ein neues Array erstellen, das ein Element kürzer ist, und die alten Elemente in das neue Array kopieren, mit Ausnahme des Elements, das Sie löschen möchten.
Daher ist es wahrscheinlich besser, eine Liste anstelle eines Arrays zu verwenden.
quelle
List<mydatatype> array = new List<mydatatype>(arrayofmydatatype)
var myList = myArray.ToList();
mit derEnumerable.ToList()
Methode aus demSystem.Linq
Namespace.Ich benutze diese Methode, um ein Element aus einem Objektarray zu entfernen. In meiner Situation sind meine Arrays klein. Wenn Sie also große Arrays haben, benötigen Sie möglicherweise eine andere Lösung.
quelle
Einzeilige LINQ-Lösung:
Das
1
in diesem Beispiel ist der Index des zu entfernenden Elements - in diesem Beispiel gemäß der ursprünglichen Frage das zweite Element (wobei1
es das zweite Element bei der C # -Null-basierten Array-Indizierung ist).Ein vollständigeres Beispiel:
Danach Snippet ausgeführt wird , der Wert
myArray
sein wird{ "a", "c", "d", "e" }
.quelle
Auf diese Weise können Sie ein Array-Element ab .Net 3.5 löschen, ohne es in ein anderes Array zu kopieren. Verwenden Sie dazu dieselbe Array-Instanz mit
Array.Resize<T>
:quelle
ref
beim Aufrufen derResize
Methode verwenden. Die Länge einer Array-Instanz ist fest und unveränderlich.Hier ist eine alte Version, die auf Version 1.0 des .NET Frameworks funktioniert und keine generischen Typen benötigt.
Dies wird folgendermaßen verwendet:
quelle
Nicht genau der richtige Weg, aber wenn die Situation trivial ist und Sie Ihre Zeit schätzen, können Sie dies für nullbare Typen versuchen.
und später nach Null-Einträgen in Ihrer Logik suchen.
quelle
Wie immer bin ich zu spät zur Party ...
Ich möchte der bereits vorhandenen Liste der netten Lösungen eine weitere Option hinzufügen. =)
Ich würde dies als eine gute Gelegenheit für Erweiterungen sehen.
Referenz: http://msdn.microsoft.com/en-us/library/bb311042.aspx
Also definieren wir eine statische Klasse und darin unsere Methode.
Danach können wir unsere erweiterte Methode wohl oder übel anwenden. =)
quelle
Versuchen Sie den folgenden Code:
oder
quelle
So habe ich es gemacht ...
quelle
In einem normalen Array müssen Sie alle Array-Einträge über 2 mischen und dann die Größe mithilfe der Resize-Methode ändern. Möglicherweise ist es besser, eine ArrayList zu verwenden.
quelle
quelle
Hier ist eine kleine Sammlung von Hilfsmethoden, die ich basierend auf einigen der vorhandenen Antworten erstellt habe. Es verwendet sowohl Erweiterungen als auch statische Methoden mit Referenzparametern für maximale Idealität:
In Bezug auf die Leistung ist es anständig, aber es könnte wahrscheinlich verbessert werden.
Remove
verlässt sich daraufIndexOf
und für jedes Element, das Sie durch Aufrufen entfernen möchten, wird ein neues Array erstelltRemoveAt
.IndexOf
ist die einzige Erweiterungsmethode, da das ursprüngliche Array nicht zurückgegeben werden muss.New
akzeptiert mehrere Elemente eines Typs, um ein neues Array dieses Typs zu erzeugen. Alle anderen Methoden müssen das ursprüngliche Array als Referenz akzeptieren, sodass das Ergebnis nicht später zugewiesen werden muss, da dies bereits intern geschieht.Ich hätte eine
Merge
Methode zum Zusammenführen von zwei Arrays definiert. Dies kann jedoch bereits mit derAdd
Methode erreicht werden, indem ein tatsächliches Array gegenüber mehreren einzelnen Elementen übergeben wird. DaherAdd
kann auf zwei Arten verwendet werden, um zwei Sätze von Elementen zu verbinden:Oder
quelle
Ich weiß, dass dieser Artikel zehn Jahre alt und daher wahrscheinlich tot ist, aber ich würde Folgendes versuchen:
Verwenden Sie die IEnumerable.Skip () -Methode in System.Linq . Das ausgewählte Element wird aus dem Array übersprungen und eine weitere Kopie des Arrays zurückgegeben, die nur alles außer dem ausgewählten Objekt enthält. Wiederholen Sie dies dann einfach für jedes Element, das Sie entfernen möchten, und speichern Sie es anschließend in einer Variablen.
Zum Beispiel, wenn wir ein Array mit dem Namen "Sample" (vom Typ int []) mit 5 Zahlen haben. Wir wollen den zweiten entfernen und versuchen "Sample.Skip (2);" sollte das gleiche Array zurückgeben, außer ohne die 2. Nummer.
quelle
Erster Schritt
Sie müssen das Array in eine Liste konvertieren. Sie können eine Erweiterungsmethode wie diese schreiben
Zweiter Schritt
Schreiben Sie eine Erweiterungsmethode, um die Liste wieder in ein Array zu konvertieren
Letzte Schritte
Schreiben Sie Ihre endgültige Methode, aber denken Sie daran, das Element am Index zu entfernen, bevor Sie es wieder in ein Array wie den Code show konvertieren
Beispielcodes finden Sie in meinem Blog .
quelle
.ToArray()
List<T>