Mam tablicę obiektów Foo. Jak usunąć drugi element tablicy?
Potrzebuję czegoś podobnego, RemoveAt()ale dla zwykłej tablicy.
Mam tablicę obiektów Foo. Jak usunąć drugi element tablicy?
Potrzebuję czegoś podobnego, RemoveAt()ale dla zwykłej tablicy.
Odpowiedzi:
Jeśli nie chcesz korzystać z listy:
var foos = new List<Foo>(array);
foos.RemoveAt(index);
return foos.ToArray();
Możesz wypróbować tę metodę rozszerzenia, której tak naprawdę nie testowałem:
public static 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;
}
I używaj go jak:
Foo[] bar = GetFoos();
bar = bar.RemoveAt(2);
Naturą tablic jest to, że ich długość jest niezmienna. Nie możesz dodawać ani usuwać żadnych elementów tablicy.
Będziesz musiał utworzyć nową tablicę, która jest o jeden element krótsza, i skopiować stare elementy do nowej tablicy, z wyłączeniem elementu, który chcesz usunąć.
Więc prawdopodobnie lepiej jest użyć listy zamiast tablicy.
List<mydatatype> array = new List<mydatatype>(arrayofmydatatype)
var myList = myArray.ToList();używając Enumerable.ToList()metody z System.Linqprzestrzeni nazw.
Używam tej metody do usuwania elementu z tablicy obiektów. W mojej sytuacji moje tablice mają małą długość. Więc jeśli masz duże tablice, możesz potrzebować innego rozwiązania.
private int[] RemoveIndices(int[] IndicesArray, int RemoveAt)
{
int[] newIndicesArray = new int[IndicesArray.Length - 1];
int i = 0;
int j = 0;
while (i < IndicesArray.Length)
{
if (i != RemoveAt)
{
newIndicesArray[j] = IndicesArray[i];
j++;
}
i++;
}
return newIndicesArray;
}
Rozwiązanie jednowierszowe LINQ:
myArray = myArray.Where((source, index) => index != 1).ToArray();
W 1tym przykładzie jest to indeks elementu do usunięcia - w tym przykładzie, zgodnie z oryginalnym pytaniem, drugi element ( 1będący drugim elementem w C # indeksowaniu tablicy od zera).
Bardziej kompletny przykład:
string[] myArray = { "a", "b", "c", "d", "e" };
int indexToRemove = 1;
myArray = myArray.Where((source, index) => index != indexToRemove).ToArray();
Po uruchomieniu tego fragmentu wartość myArraywill będzie { "a", "c", "d", "e" }.
Jest to sposób na usunięcie elementu tablicy, począwszy od .Net 3.5, bez kopiowania do innej tablicy - używając tej samej instancji tablicy z Array.Resize<T>:
public static void RemoveAt<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 one
Array.Resize(ref arr, arr.Length - 1);
}
reftej Resizemetody. Długość wystąpienia tablicy jest stała i niezmienna.
Oto moja stara wersja, która działa na wersji 1.0 platformy .NET i nie wymaga typów ogólnych.
public static Array RemoveAt(Array source, int index)
{
if (source == null)
throw new ArgumentNullException("source");
if (0 > index || index >= source.Length)
throw new ArgumentOutOfRangeException("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;
}
Jest to używane w następujący sposób:
class Program
{
static void Main(string[] args)
{
string[] x = new string[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]);
}
}
Nie do końca jest to sposób na zrobienie tego, ale jeśli sytuacja jest trywialna i cenisz swój czas, możesz spróbować tego dla typów dopuszczających wartość null.
Foos[index] = null
a później sprawdź puste wpisy w logice.
Jak zwykle spóźniam się na imprezę ...
Chciałbym dodać kolejną opcję do już istniejącej listy fajnych rozwiązań. =)
Uznałbym to za dobrą okazję do rozszerzeń.
Źródła:
http://msdn.microsoft.com/en-us/library/bb311042.aspx
Dlatego definiujemy pewną statyczną klasę, aw niej naszą metodę.
Potem możemy użyć naszej rozszerzonej metody chcąc nie chcąc. =)
using System;
namespace FunctionTesting {
// The class doesn't matter, as long as it's static
public static class SomeRandomClassWhoseNameDoesntMatter {
// Here's the actual method that extends arrays
public static T[] RemoveAt<T>( this T[] oArray, int idx ) {
T[] nArray = new T[oArray.Length - 1];
for( int i = 0; i < nArray.Length; ++i ) {
nArray[i] = ( i < idx ) ? oArray[i] : oArray[i + 1];
}
return nArray;
}
}
// Sample usage...
class Program {
static void Main( string[] args ) {
string[] myStrArray = { "Zero", "One", "Two", "Three" };
Console.WriteLine( String.Join( " ", myStrArray ) );
myStrArray = myStrArray.RemoveAt( 2 );
Console.WriteLine( String.Join( " ", myStrArray ) );
/* Output
* "Zero One Two Three"
* "Zero One Three"
*/
int[] myIntArray = { 0, 1, 2, 3 };
Console.WriteLine( String.Join( " ", myIntArray ) );
myIntArray = myIntArray.RemoveAt( 2 );
Console.WriteLine( String.Join( " ", myIntArray ) );
/* Output
* "0 1 2 3"
* "0 1 3"
*/
}
}
}
Wypróbuj poniższy kod:
myArray = myArray.Where(s => (myArray.IndexOf(s) != indexValue)).ToArray();
lub
myArray = myArray.Where(s => (s != "not_this")).ToArray();
Oto jak to zrobiłem ...
public static ElementDefinitionImpl[] RemoveElementDefAt(
ElementDefinition[] oldList,
int removeIndex
)
{
ElementDefinitionImpl[] newElementDefList = new ElementDefinitionImpl[ oldList.Length - 1 ];
int offset = 0;
for ( int index = 0; index < oldList.Length; index++ )
{
ElementDefinitionImpl elementDef = oldList[ index ] as ElementDefinitionImpl;
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;
}
private int[] removeFromArray(int[] array, int id)
{
int difference = 0, currentValue=0;
//get new Array length
for (int i=0; i<array.Length; i++)
{
if (array[i]==id)
{
difference += 1;
}
}
//create new array
int[] newArray = new int[array.Length-difference];
for (int i = 0; i < array.Length; i++ )
{
if (array[i] != id)
{
newArray[currentValue] = array[i];
currentValue += 1;
}
}
return newArray;
}
Oto mały zbiór metod pomocniczych, które stworzyłem na podstawie niektórych istniejących odpowiedzi. Wykorzystuje zarówno rozszerzenia, jak i metody statyczne z parametrami referencyjnymi dla maksymalnej idealności:
public static class Arr
{
public static int IndexOf<TElement>(this TElement[] Source, TElement Element)
{
for (var i = 0; i < Source.Length; i++)
{
if (Source[i].Equals(Element))
return i;
}
return -1;
}
public static TElement[] Add<TElement>(ref TElement[] Source, params TElement[] Elements)
{
var OldLength = Source.Length;
Array.Resize(ref Source, OldLength + Elements.Length);
for (int j = 0, Count = Elements.Length; j < Count; j++)
Source[OldLength + j] = Elements[j];
return Source;
}
public static TElement[] New<TElement>(params TElement[] Elements)
{
return Elements ?? new TElement[0];
}
public static void Remove<TElement>(ref TElement[] Source, params TElement[] Elements)
{
foreach (var i in Elements)
RemoveAt(ref Source, Source.IndexOf(i));
}
public static void RemoveAt<TElement>(ref TElement[] Source, int Index)
{
var Result = new TElement[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;
}
}
Pod względem wydajności jest przyzwoity, ale prawdopodobnie można by go poprawić. Removeopiera się IndexOfi tworzona jest nowa tablica dla każdego elementu, który chcesz usunąć przez wywołanie RemoveAt.
IndexOfjest jedyną metodą rozszerzającą, ponieważ nie musi zwracać oryginalnej tablicy. Newakceptuje wiele elementów pewnego typu, aby utworzyć nową tablicę tego typu. Wszystkie inne metody muszą akceptować oryginalną tablicę jako odniesienie, więc nie ma potrzeby późniejszego przypisywania wyniku, ponieważ dzieje się to już wewnętrznie.
Zdefiniowałbym Mergemetodę łączenia dwóch tablic; Jednak można to już osiągnąć za pomocą Addmetody, przekazując rzeczywistą tablicę w porównaniu z wieloma pojedynczymi elementami. Dlatego Addmożna go użyć na dwa sposoby, aby połączyć dwa zestawy elementów:
Arr.Add<string>(ref myArray, "A", "B", "C");
Lub
Arr.Add<string>(ref myArray, anotherArray);
Wiem, że ten artykuł ma dziesięć lat i dlatego prawdopodobnie nie żyje, ale oto, co spróbuję zrobić:
Użyj metody IEnumerable.Skip (), którą można znaleźć w System.Linq . Pominie wybrany element z tablicy i zwróci kolejną kopię tablicy, która zawiera tylko wszystko oprócz zaznaczonego obiektu. Następnie powtórz to dla każdego elementu, który chcesz usunąć, a następnie zapisz go w zmiennej.
Na przykład, jeśli mamy tablicę o nazwie „Próbka” (typu int []) z 5 liczbami. Chcemy usunąć drugi, więc próbujemy "Sample.Skip (2);" powinien zwrócić tę samą tablicę, ale bez drugiej liczby.
Pierwszy krok
Musisz przekonwertować tablicę na listę, możesz napisać taką metodę rozszerzającą
// Convert An array of string to a list of string
public static List<string> ConnvertArrayToList(this string [] array) {
// DECLARE a list of string and add all element of the array into it
List<string> myList = new List<string>();
foreach( string s in array){
myList.Add(s);
}
return myList;
}
Drugi krok
Napisz metodę rozszerzenia, aby przekonwertować listę z powrotem na tablicę
// convert a list of string to an array
public static string[] ConvertListToArray(this List<string> list) {
string[] array = new string[list.Capacity];
array = list.Select(i => i.ToString()).ToArray();
return array;
}
Ostatnie kroki
Napisz ostateczną metodę, ale pamiętaj, aby usunąć element w indeksie przed konwersją z powrotem do tablicy, takiej jak w kodzie
public static string[] removeAt(string[] array, int index) {
List<string> myList = array.ConnvertArrayToList();
myList.RemoveAt(index);
return myList.ConvertListToArray();
}
Przykładowe kody można znaleźć na moim blogu , śledźcie dalej.
.ToArray()i List<T>konstruktora, który bierze istniejącą sekwencję ...
System.Collections.ObjectModel.Collection<Foo>.