2009-01-19 34 views
90

Tôi có một mảng đối tượng Foo. Làm thế nào để loại bỏ phần tử thứ hai của mảng?Xóa phần tử của một mảng thông thường

Tôi cần một cái gì đó tương tự như RemoveAt() nhưng đối với một mảng thông thường.

+0

Sử dụng 'System.Collections.ObjectModel.Collection '. – abatishchev

+0

Đối với trò chơi của tôi, tôi đã đi với một cơ sở hạ tầng "null at index". Về cơ bản, mảng bên trong (buffer) có kích thước tĩnh, và thay vì loại bỏ chỉ mục và thay đổi kích thước mảng, tôi chỉ làm cho chỉ mục rỗng. Khi tôi cần thêm một mục, tôi chỉ tìm thấy chỉ mục không null đầu tiên và đặt nó ở đó. Hoạt động khá tốt, nhưng rõ ràng không phải cho mọi thứ. – Krythic

Trả lời

148

Nếu bạn không muốn sử dụng liệt kê:

var foos = new List<Foo>(array); 
foos.RemoveAt(index); 
return foos.ToArray(); 

Bạn có thể thử phương pháp này mở rộng mà tôi đã không thực sự thử nghiệm:

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; 
} 

Và sử dụng nó như:

Foo[] bar = GetFoos(); 
bar = bar.RemoveAt(2); 
+6

Ví dụ đầu tiên được đưa ra trong câu trả lời này kém hiệu quả hơn số thứ hai. Nó đòi hỏi hai bản sao mảng và một sự thay đổi của tất cả mọi thứ sau khi chỉ mục chứ không phải là một bản sao mảng chọn lọc. –

+1

+1 tất nhiên, nhưng chúng tôi cũng có thể sử dụng danh sách quá HOẶC Danh sách danh sách = danh sách mới (GetFoos()); list.Remove (my_foo); list.RemoveAt (2); nơi GetFoos() sẽ trả về mảng Foos !!!! – shahjapan

+1

Dòng đầu tiên bên trong phương thức nên nói 'source.Length' thay vì 'array.Length'. – Nelson

1

Đây là cách tôi đã làm nó ...

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; 
    } 
54

Bản chất của mảng là độ dài của chúng là không thay đổi. Bạn không thể thêm hoặc xóa bất kỳ mục mảng nào.

Bạn sẽ phải tạo một mảng mới ngắn hơn một phần tử và sao chép các mục cũ vào mảng mới, trừ phần tử bạn muốn xóa.

Vì vậy, có lẽ tốt hơn nên sử dụng Danh sách thay vì mảng.

+3

Chuyển đổi mảng thành danh sách 'Danh sách array = new List (arrayofmydatatype)' –

1

Trong một mảng bình thường, bạn phải trộn tất cả các mục nhập trên 2 và sau đó thay đổi kích thước bằng cách sử dụng phương pháp Resize. Bạn có thể sử dụng ArrayList tốt hơn.

5

Đây là phiên bản cũ mà tôi hoạt động trên phiên bản 1.0 của khung .NET và không cần chi tiết c loại.

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; 
} 

này được sử dụng như thế này:

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]); 
    } 
} 
43

tôi sử dụng phương pháp này để loại bỏ một phần tử từ một mảng đối tượng. Trong tình huống của tôi, mảng của tôi có chiều dài nhỏ. Vì vậy, nếu bạn có mảng lớn, bạn có thể cần một giải pháp khác.

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; 
} 
+5

Cá nhân tôi thích câu trả lời này tốt hơn câu trả lời được chấp nhận. Nó phải hiệu quả và dễ đọc hơn nhiều. Tôi có thể nhìn vào nó và biết nó là chính xác. Tôi sẽ phải kiểm tra một cái khác để đảm bảo những bản sao đó được viết chính xác. – oillio

+0

Nó thực sự là một sự xấu hổ câu trả lời này là quá thấp, khi nó tốt hơn nhiều so với hai ở trên nó. – Sepulchritude

3

Không chính xác cách để giải quyết vấn đề này, nhưng nếu tình huống không đáng kể và bạn coi trọng thời gian, bạn có thể thử điều này cho các loại có thể vô hiệu.

Foos[index] = null 

và sau đó kiểm tra các mục nhập rỗng trong logic của bạn ..

+0

Đây là cách tôi đã làm nó cho trò chơi của tôi. Đi với bộ đệm trống cho các khu vực được thay đổi rất thường xuyên. – Krythic

-4

Bước đầu tiên
Bạn cần phải chuyển đổi mảng vào một danh sách, bạn có thể viết một phương pháp khuyến nông như

// 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; 
} 

Thứ hai bước
này Viết một phương pháp khuyến nông để chuyển đổi trở lại danh sách thành một mảng

// 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; 
} 

bước cuối cùng
Viết phương pháp cuối cùng của bạn, nhưng hãy nhớ để loại bỏ các phần tử ở chỉ số trước khi chuyển đổi trở lại một mảng như mã hiển thị

public static string[] removeAt(string[] array, int index) { 

    List<string> myList = array.ConnvertArrayToList(); 
    myList.RemoveAt(index); 
    return myList.ConvertListToArray(); 
} 

mã ví dụ có thể được tìm thấy trên my blog, giữ theo dõi.

+12

Điều này hơi điên khi xem xét sự tồn tại của '.ToArray()' và một hàm tạo danh sách 'List ' có một chuỗi hiện tại ... – user7116

7

Đây là một cách để xóa một phần tử mảng, tính đến Net 3.5, mà không cần sao chép vào mảng khác - bằng cách sử dụng ví dụ mảng cùng với 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); 
} 
+0

"không sao chép vào mảng khác" - theo tài liệu được liên kết, Array.Resize thực sự * * cấp phát một mảng mới đằng sau hậu trường và sao chép các phần tử từ mảng cũ sang mảng mới. Tuy nhiên, tôi thích sự đồng nhất của giải pháp này. –

+0

Rất đẹp và rõ ràng nếu bạn chắc chắn đó là một mảng tương đối nhỏ. – Darren

+0

Tiếp tục bình luận của @ JonSchneider, nó không phải là "cùng một thể hiện mảng". Đó là lý do tại sao bạn cần sử dụng 'ref' khi bạn gọi phương thức' Resize'. Độ dài của một thể hiện mảng là cố định và không thay đổi được. –

2

Như thường lệ, tôi đến trễ đến bên ...

Tôi muốn thêm tùy chọn khác vào danh sách giải pháp tốt đẹp đã có. =)
Tôi sẽ thấy đây là cơ hội tốt cho Tiện ích mở rộng.

tham khảo: http://msdn.microsoft.com/en-us/library/bb311042.aspx

Vì vậy, chúng ta định nghĩa một số lớp tĩnh và trong đó, Phương pháp của chúng tôi.
Sau đó, chúng tôi có thể sử dụng phương pháp mở rộng của chúng tôi. =)

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" 
      */ 
     } 
    } 
} 
31

LINQ giải pháp một dòng:

myArray = myArray.Where((source, index) => index != 1).ToArray(); 

Các 1 trong ví dụ đó là chỉ số của nguyên tố này để loại bỏ - trong ví dụ này, mỗi câu hỏi ban đầu, yếu tố thứ 2 (với 1 là phần tử thứ hai trong lập chỉ mục mảng dựa trên C# không).

Một ví dụ hoàn chỉnh hơn:

string[] myArray = { "a", "b", "c", "d", "e" }; 
int indexToRemove = 1; 
myArray = myArray.Where((source, index) => index != indexToRemove).ToArray(); 

Sau khi chạy đoạn mã đó, giá trị của myArray sẽ { "a", "c", "d", "e" }.

+0

Đối với các khu vực yêu cầu truy cập thường xuyên/hiệu năng cao, LINQ không được khuyến nghị. – Krythic

+1

@Krythic Đó là một nhận xét công bằng. Chạy hàng ngàn lần trong một vòng lặp chặt chẽ, hiệu suất của giải pháp này không tốt bằng một số giải pháp được bình chọn cao khác trên trang này: https://dotnetfiddle.net/z9Xkpn –

1
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; 
    } 
0

Đây là một bộ sưu tập nhỏ các phương pháp trợ giúp tôi đã tạo dựa trên một số câu trả lời hiện có. Nó sử dụng cả phần mở rộng và phương pháp tĩnh với các thông số tham chiếu cho idealness tối đa:

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; 
    } 
} 

Hiệu suất khôn ngoan, đó là phong nha, nhưng nó có thể có thể được cải thiện.Remove dựa trên IndexOf và một mảng mới được tạo cho từng phần tử bạn muốn xóa bằng cách gọi RemoveAt.

IndexOf là phương pháp tiện ích mở rộng duy nhất vì không cần trả lại mảng ban đầu. New chấp nhận nhiều thành phần của một số loại để tạo ra một mảng mới thuộc loại đã nói. Tất cả các phương thức khác phải chấp nhận mảng gốc làm tham chiếu vì vậy không cần gán kết quả sau đó vì điều đó xảy ra trong nội bộ.

Tôi đã xác định phương thức Merge để hợp nhất hai mảng; tuy nhiên, điều đó có thể đã được thực hiện với phương thức Add bằng cách truyền vào một mảng thực tế so với nhiều phần tử riêng lẻ. Do đó, Add có thể được sử dụng trong hai cách sau đây để tham gia hai bộ của các yếu tố:

Arr.Add<string>(ref myArray, "A", "B", "C"); 

Hoặc

Arr.Add<string>(ref myArray, anotherArray); 
Các vấn đề liên quan