У мене є масив об'єктів Foo. Як видалити другий елемент масиву?
Мені потрібно щось подібне, RemoveAt()
але для звичайного масиву.
У мене є масив об'єктів Foo. Як видалити другий елемент масиву?
Мені потрібно щось подібне, RemoveAt()
але для звичайного масиву.
Відповіді:
Якщо ви не хочете використовувати Список:
var foos = new List<Foo>(array);
foos.RemoveAt(index);
return foos.ToArray();
Ви можете спробувати цей метод розширення, який я фактично не перевіряв:
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;
}
І використовувати його так:
Foo[] bar = GetFoos();
bar = bar.RemoveAt(2);
Характер масивів полягає в тому, що їх довжина незмінна. Ви не можете додати або видалити жоден елемент масиву.
Вам доведеться створити новий масив, який на один елемент коротший, і скопіювати старі елементи в новий масив, виключаючи елемент, який потрібно видалити.
Тому, ймовірно, краще використовувати Список замість масиву.
List<mydatatype> array = new List<mydatatype>(arrayofmydatatype)
var myList = myArray.ToList();
використовуючи Enumerable.ToList()
метод з System.Linq
простору імен.
Я використовую цей метод для видалення елемента з об’єктного масиву. У моїй ситуації мої масиви мають невелику довжину. Тож якщо у вас є великі масиви, можливо, вам знадобиться інше рішення.
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;
}
Однорядне рішення LINQ:
myArray = myArray.Where((source, index) => index != 1).ToArray();
У 1
цьому прикладі є індекс елемента, який потрібно видалити - у цьому прикладі за оригінальним запитанням, другий елемент (з 1
тим, що є другим елементом в індексації масиву на основі нуля C #).
Більш повний приклад:
string[] myArray = { "a", "b", "c", "d", "e" };
int indexToRemove = 1;
myArray = myArray.Where((source, index) => index != indexToRemove).ToArray();
Після запуску цього фрагмента значення myArray
буде { "a", "c", "d", "e" }
.
Це спосіб видалити елемент масиву, як .Net 3.5, без копіювання в інший масив - використовуючи той самий екземпляр масиву з 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);
}
ref
при виклику Resize
методу. Довжина екземпляра масиву є фіксованою та незмінною.
Ось у мене стара версія, яка працює на версії 1.0 рамки .NET і не потребує загальних типів.
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;
}
Це використовується так:
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]);
}
}
Не зовсім так, як це зробити, але якщо ситуація тривіальна і ви цінуєте свій час, ви можете спробувати це для змінних типів.
Foos[index] = null
а пізніше перевірити наявність логічних записів у вашій логіці ..
Як завжди, я спізнююсь на вечірку ...
Я хотів би додати ще один варіант до списку приємних рішень, який вже є. =)
Я вважаю це гарною можливістю для розширень.
Довідка:
http://msdn.microsoft.com/en-us/library/bb311042.aspx
Отже, ми визначаємо деякий статичний клас і в ньому наш Метод.
Після цього ми можемо використовувати наш розширений метод мимоволі. =)
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"
*/
}
}
}
Спробуйте нижче код:
myArray = myArray.Where(s => (myArray.IndexOf(s) != indexValue)).ToArray();
або
myArray = myArray.Where(s => (s != "not_this")).ToArray();
Ось як я це зробив ...
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;
}
Ось невеликий набір допоміжних методів, які я підготував на основі деяких існуючих відповідей. Він використовує як розширення, так і статичні методи з еталонними параметрами для максимальної ідеальності:
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;
}
}
Продуктивність мудра, вона гідна, але, можливо, її можна було б покращити. Remove
покладається на IndexOf
і створюється новий масив для кожного елемента, який ви бажаєте видалити, зателефонувавши RemoveAt
.
IndexOf
є єдиним методом розширення, оскільки йому не потрібно повертати початковий масив. New
приймає кілька елементів деякого типу для створення нового масиву згаданого типу. Усі інші методи повинні сприймати оригінальний масив як опорний, тому немає необхідності присвоювати результат згодом, як це вже відбувається внутрішньо.
Я б визначив Merge
метод об'єднання двох масивів; однак це вже можна досягти Add
методом, передаючи фактичний масив проти кількох окремих елементів. Тому Add
можуть використовуватися наступні два способи з'єднання двох наборів елементів:
Arr.Add<string>(ref myArray, "A", "B", "C");
Або
Arr.Add<string>(ref myArray, anotherArray);
Я знаю, що цій статті десять років і тому, ймовірно, мертвий, але ось що я б спробував зробити:
Використовуйте метод IEnumerable.Skip (), знайдений у System.Linq . Він буде пропускати вибраний елемент з масиву та повертає іншу копію масиву, яка містить лише все, крім вибраного об'єкта. Потім просто повторіть, що для кожного елемента, який ви хочете видалити, а потім збережіть його до змінної.
Наприклад, якщо у нас є масив під назвою "Sample" (типу int []) з 5 числами. Ми хочемо видалити 2-ю, тому спробуємо "Sample.Skip (2);" повинен повернути той самий масив, крім 2-го числа.
Перший крок
Вам потрібно перетворити масив у список, ви можете написати такий метод розширення
// 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;
}
Другий крок
Напишіть метод розширення для перетворення списку в масив
// 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;
}
Останні кроки
Напишіть свій остаточний метод, але не забудьте видалити елемент в індексі перед перетворенням назад в масив, як показано код
public static string[] removeAt(string[] array, int index) {
List<string> myList = array.ConnvertArrayToList();
myList.RemoveAt(index);
return myList.ConvertListToArray();
}
приклади кодів можна знайти в моєму блозі , продовжуйте стежити.
.ToArray()
та List<T>
конструктор, який приймає існуючу послідовність ...
System.Collections.ObjectModel.Collection<Foo>
.