web-dev-qa-db-ja.com

通常の配列の要素を削除する

Fooオブジェクトの配列があります。配列の2番目の要素を削除するにはどうすればよいですか?

RemoveAt()に似たものが必要ですが、通常の配列用です。

114
leora

リストを使用したくない場合:

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);
170
Andrew Kennan

配列の性質は、その長さが不変であるということです。配列項目を追加または削除することはできません。

1要素短い新しい配列を作成し、削除する要素を除いて、古いアイテムを新しい配列にコピーする必要があります。

したがって、おそらく配列の代わりにリストを使用する方が良いでしょう。

61
Sebastian Dietz

このメソッドを使用して、オブジェクト配列から要素を削除します。私の状況では、私の配列は長さが短いです。したがって、大きなアレイがある場合は、別のソリューションが必要になる場合があります。

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

LINQの1行ソリューション:

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

この例の1は、削除する要素のインデックスです。この例では、元の質問ごとに、2番目の要素(1がC#0ベースの配列インデックス付けの2番目の要素です)。

より完全な例:

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

そのスニペットを実行すると、myArrayの値は{ "a", "c", "d", "e" }になります。

44
Jon Schneider

これは、.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);
}
9
infografnet

。NET フレームワークのバージョン1.0で動作し、ジェネリック型を必要としない古いバージョンを次に示します。

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]);
    }
}
5
Martin Brown

正確にこれを実行する方法ではありませんが、状況が些細で時間を大切にしている場合は、null許容型に対してこれを試すことができます。

Foos[index] = null

後でロジックのヌルエントリを確認します。

3
nawfal

いつものように、私はパーティーに遅れています...

すでに存在するニースソリューションリストに別のオプションを追加したいと思います。 =)
これはエクステンションの良い機会だと思います。

参照: 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"
             */
        }
    }
}
2
Duncan
    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;
    }
1
user2884232

ここに私がそれをした方法があります...

    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;
    }
1
Paul Mitchell

通常の配列では、2より上のすべての配列エントリをシャッフルダウンし、Resizeメソッドを使用してサイズを変更する必要があります。 ArrayListを使用したほうがよい場合があります。

1
gkrogers

私はこの記事が10年前であり、おそらく死んでいることを知っていますが、私がやろうとしていることは次のとおりです:

System.LinqにあるIEnumerable.Skip()メソッドを使用。配列から選択された要素をスキップし、選択されたオブジェクト以外のすべてを含む配列の別のコピーを返します。次に、削除するすべての要素に対してそれを繰り返し、その後、変数に保存します。

たとえば、5つの数字を持つ「Sample」(int []型)という名前の配列がある場合。 2番目のものを削除したいので、「Sample.Skip(2);」を試してください。 2番目の番号がない場合を除き、同じ配列を返す必要があります。

0
commandertuna

以下は、既存の回答のいくつかに基づいて作成したヘルパーメソッドの小さなコレクションです。最大の理想性を得るために、参照パラメーターを使用して拡張メソッドと静的メソッドの両方を利用します。

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

パフォーマンスに関しては、まともですが、おそらく改善される可能性があります。 RemoveIndexOfに依存しており、RemoveAtを呼び出して削除する各要素に対して新しい配列が作成されます。

IndexOfは、元の配列を返す必要がないため、唯一の拡張メソッドです。 Newは、あるタイプの複数の要素を受け入れて、そのタイプの新しい配列を生成します。他のすべてのメソッドは、元の配列を参照として受け入れる必要があるため、後で内部的に行われるため、後で結果を割り当てる必要はありません。

2つの配列をマージするMergeメソッドを定義します。ただし、これはAddメソッドを使用して、実際の配列と複数の個々の要素を渡すことで既に実現できます。したがって、次の2つの方法でAddを使用して、2つの要素セットを結合できます。

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

または

Arr.Add<string>(ref myArray, anotherArray);
0
James M