从常规数组中删除元素

157

我有一个 Foo 对象的数组。如何删除这个数组的第二个元素?

我需要类似于 RemoveAt() 但适用于普通数组的方法。


1
使用 System.Collections.ObjectModel.Collection<Foo> - abatishchev
2
对于我的游戏,我选择了“索引处为空”的数据结构。基本上,内部数组(缓冲区)是静态大小的,而不是删除索引并调整数组大小,我只是将索引设置为null。当我需要添加一个项目时,我只需找到第一个非空索引并将其放置在那里。效果还不错,但显然并不适用于所有情况。 - Krythic
16个回答

1
在普通数组中,您必须将所有大于2的数组条目向下洗牌,然后使用Resize方法调整大小。您最好使用ArrayList。

1

这是我的做法...

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

0
嗯,为什么大家都在分配一个新的数组呢?
只需将“被移除”的元素后面的部分复制到一个索引下,并在最后一个元素中放入null或默认值。
这样,您既可以享受固定长度数组的好处(如果不使用列表,这可能很重要),又不需要遍历每个元素来检查null(您可以在第一个null处中断循环)。

0
这是我基于一些现有答案编写的一小组辅助方法。它利用扩展和静态方法,并使用引用参数以实现最大的理想性:
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);

-2

我知道这篇文章已经十年了,可能已经过时了,但是这是我会尝试做的:

使用IEnumerable.Skip()方法,它在System.Linq中找到。它将跳过数组中选择的元素,并返回另一个仅包含除所选对象以外的所有内容的数组副本。然后只需为要删除的每个元素重复此操作,然后将其保存到变量中。

例如,如果我们有一个名为“Sample”的数组(类型为int []),其中包含5个数字。我们想要删除第二个数字,因此尝试“Sample.Skip(2);”应该返回相同的数组,但不包括第二个数字。


1
这个方法不是只跳过序列中指定数量的元素,然后返回剩余的元素吗?在你的例子中,你将“跳过”通用列表的前两个元素,而不仅仅是第二个! - xnr_z

-4

第一步
您需要将数组转换为列表,您可以编写一个扩展方法,如下所示:

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

示例代码可以在我的博客上找到,请持续关注。


14
考虑到存在.ToArray()List<T>构造函数可以接受现有序列,这种做法有些不太理智。 - user7116

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接