एक नियमित सरणी का तत्व निकालें


135

मेरे पास फू वस्तुओं का एक समूह है। मैं सरणी का दूसरा तत्व कैसे निकालूं?

मुझे कुछ इसी तरह की जरूरत है, RemoveAt()लेकिन एक नियमित सरणी के लिए।


1
का उपयोग करें System.Collections.ObjectModel.Collection<Foo>
अबिशशेव

1
अपने खेल के लिए मैं "इंडेक्स में अशक्त" डेटास्ट्रक्चर के साथ गया था। मूल रूप से, आंतरिक सरणी (बफर) स्थिर आकार की है, और सूचकांक को हटाने और सरणी का आकार बदलने के बजाय, मैं सिर्फ सूचकांक को सुस्त बनाता हूं। जब मुझे एक आइटम जोड़ने की आवश्यकता होती है तो मैं केवल पहला गैर-अशक्त सूचकांक ढूंढता हूं और इसे वहां रखता हूं। बहुत अच्छी तरह से काम करता है, लेकिन जाहिर है कि सब कुछ के लिए नहीं।
क्राइथिक

जवाबों:


202

यदि आप सूची का उपयोग नहीं करना चाहते हैं:

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

8
इस उत्तर में दिया गया पहला उदाहरण दूसरे की तुलना में बहुत कम कुशल है। इसके लिए दो एरे कॉपी और एक सेलेक्टिव एरे कॉपी के बजाय इंडेक्स के बाद हर चीज की शिफ्ट की जरूरत होती है।
मार्टिन ब्राउन

2
+1 का बेशक, लेकिन हम सूची का उपयोग भी कर सकते हैं या सूची <Foo> सूची = नई सूची <Foll> (GetFoos ()); list.Remove (my_foo); list.RemoveAt (2); जहां GetFoos () फोस की सरणी वापस आ जाएगी !!!!
शाहजहां

2
विधि के अंदर पहली पंक्ति को 'array.Length' के बजाय 'source.Length' कहना चाहिए।
नेल्सन

1
यह भी ध्यान रखें कि किसी भी चर को मूल सरणी के संदर्भ में रखने से मूल डेटा जारी रहेगा और स्रोत और आउटपुट सरणी के बीच किसी भी संदर्भ समानता की तुलना नकारात्मक हो जाएगी।
bkqc

1
@MartinBrown वास्तव में, एक सूची को \ से और सरणी में परिवर्तित करना एक सरणी प्रतिलिपि की तुलना में बहुत धीमा है (जो केवल कुछ एएसएम निर्देशों के साथ सीपीयू द्वारा अनुमत अधिकतम गति पर डेटा की प्रतिलिपि बनाने में सक्षम है)। साथ ही, किसी सूची को शिफ्ट करना बहुत तेज़ है क्योंकि यह केवल कुछ पॉइंटर्स को स्वैप करने और नोड डेटा को हटाने की बात है (जो कि इस मामले में केवल 8 बाइट्स है [हेड और टेल पॉइंटर्स के लिए एक और 16])।
krowe2

66

सरणियों की प्रकृति यह है कि उनकी लंबाई अपरिवर्तनीय है। आप किसी भी सरणी आइटम को जोड़ या हटा नहीं सकते।

आपको एक नया सरणी बनाना होगा जो एक तत्व छोटा हो और पुराने आइटम को नए सरणी में कॉपी करें, उस तत्व को छोड़कर जिसे आप हटाना चाहते हैं।

इसलिए एक सरणी के बजाय एक सूची का उपयोग करना बेहतर है।


4
सरणी को सूची में परिवर्तित करेंList<mydatatype> array = new List<mydatatype>(arrayofmydatatype)
अमर ब्लू

1
@ImortalBlue या केवल नाम स्थान से विधि var myList = myArray.ToList();का उपयोग कर । Enumerable.ToList()System.Linq
डायन्ड्रिलिया

58

मैं किसी ऑब्जेक्ट सरणी से किसी तत्व को निकालने के लिए इस विधि का उपयोग करता हूं। मेरी स्थिति में, मेरी सरणियाँ लंबाई में छोटी हैं। इसलिए यदि आपके पास बड़े सरणियां हैं, तो आपको दूसरे समाधान की आवश्यकता हो सकती है।

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

7
व्यक्तिगत रूप से, मुझे यह उत्तर स्वीकृत उत्तर से बेहतर लगता है। यह उतना ही कुशल होना चाहिए, और इसे पढ़ना बहुत आसान है। मैं इसे देख सकता हूं और जानता हूं कि यह सही है। मुझे यह सुनिश्चित करने के लिए कि उन प्रतियों को सही ढंग से लिखा गया था, मुझे दूसरे का परीक्षण करना होगा।
oillio

1
यह वास्तव में शर्म की बात है कि यह जवाब इतना कम है, जब यह ऊपर के दो से कहीं बेहतर है।
सिपाहीवाद

Aaarhg, वह जवाब है जिसकी मुझे तलाश थी! यह सूचियों के बिना सबसे अच्छा तरीका है।
जोर्डी हर्टस

47

LINQ एक-लाइन समाधान:

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

1इस उदाहरण में, मूल प्रश्न प्रति, 2 तत्व (साथ - कि उदाहरण में हटाने तत्व के सूचकांक करने के लिए है 1सी # शून्य आधारित सरणी अनुक्रमण में दूसरा तत्व रहा है)।

एक और पूर्ण उदाहरण:

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

उस स्निपेट को चलाने के बाद, का मान myArrayहोगा { "a", "c", "d", "e" }


1
उच्च-प्रदर्शन / लगातार पहुंच वाले क्षेत्रों के लिए, LINQ अनुशंसित नहीं है।
क्राइथिक

3
@Krythic यह एक उचित टिप्पणी है। एक तंग पाश में हजारों बार चलाएं, इस समाधान का प्रदर्शन इस पृष्ठ पर कुछ अन्य उच्च-मतदान समाधानों जितना अच्छा नहीं है: dotnetfiddle.net/z9Xkpn
जॉन श्नाइडर

9

यह एक सरणी तत्व को हटाने का एक तरीका है, .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);
}

2
"किसी अन्य सरणी में कॉपी किए बिना" - लिंक किए गए दस्तावेज़ के अनुसार, Array.Resize वास्तव में पर्दे के पीछे एक नया सरणी आवंटित करता है , और पुराने सरणी से नए को तत्वों को कॉपी करता है। फिर भी, मुझे इस समाधान की सहमति पसंद है।
जॉन श्नाइडर

बहुत अच्छा और स्पष्ट है अगर आपका यकीन है कि यह अपेक्षाकृत छोटा सरणी है।
डैरेन

1
@ जॉनस्नाइडर की टिप्पणी को जारी रखते हुए, यह "समान सरणी उदाहरण" नहीं है। यही कारण है कि refजब आप Resizeविधि को बुलाते हैं तो आपको उपयोग करने की आवश्यकता होती है । एक सरणी आवृत्ति की लंबाई निश्चित और अपरिवर्तनीय है।
जेपी स्टिग नील्सन

2
यदि तत्वों का क्रम महत्वपूर्ण नहीं है, तो सभी तत्वों को नीचे की ओर ले जाने के बजाय, आप तत्व को अंतिम तत्व के साथ अनुक्रमणिका में स्वैप कर सकते हैं और फिर आकार बदल सकते हैं: गिरफ्तारी [सूचकांक] = गिरफ्तारी [गिरफ्तारी] - 1]; Array.Resize (रेफ गिरफ्तारी, गिरफ्तारी। गति - 1);
बार्टेल

5

यहां मेरे पास एक पुराना संस्करण है जो .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]);
    }
}

3

इस बारे में जाने का बिल्कुल तरीका नहीं है, लेकिन अगर स्थिति तुच्छ है और आप अपने समय को महत्व देते हैं, तो आप इसे अशक्त प्रकारों के लिए आज़मा सकते हैं।

Foos[index] = null

और बाद में अपने तर्क में अशक्त प्रविष्टियों के लिए जाँच करें।


ऐसा मैंने अपने खेल के लिए किया। उन क्षेत्रों के लिए अशक्त बफ़र्स के साथ जाएं जो बहुत बार बदले जाते हैं।
क्राइथिक

2

हमेशा की तरह, मुझे पार्टी के लिए देर हो रही है ...

मैं पहले से मौजूद अच्छी समाधान सूची में एक और विकल्प जोड़ना चाहता हूं। =)
मैं इसे एक्सटेंशन्स के लिए एक अच्छा अवसर के रूप में देखूंगा।

संदर्भ: 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

कोड के नीचे आज़माएं:

myArray = myArray.Where(s => (myArray.IndexOf(s) != indexValue)).ToArray();

या

myArray = myArray.Where(s => (s != "not_this")).ToArray();

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

1

एक सामान्य सरणी में आपको 2 से ऊपर की सभी सरणी प्रविष्टियों को फेरबदल करना होगा और फिर आकार परिवर्तन विधि का उपयोग करके इसे आकार देना होगा। आप एक ArrayList का उपयोग करके बेहतर हो सकते हैं।


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

यहाँ कुछ मौजूदा उत्तरों के आधार पर मैंने सहायक सहायक विधियों का एक छोटा संग्रह प्रस्तुत किया है। यह अधिकतम आदर्शता के लिए संदर्भ मापदंडों के साथ एक्सटेंशन और स्टेटिक दोनों तरीकों का उपयोग करता है:

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

-1

मुझे पता है कि यह लेख दस साल पुराना है और इसलिए शायद मर गया है, लेकिन यहाँ मैं क्या करने की कोशिश करूँगा:

System.Linq में पाए जाने वाले IEnumerable.Skip () पद्धति का उपयोग करें । यह सरणी से चयनित तत्व को छोड़ देगा, और उस सरणी की दूसरी प्रतिलिपि लौटाएगा जिसमें केवल चयनित ऑब्जेक्ट को छोड़कर सब कुछ शामिल है। फिर बस उसे दोहराएं जो आपके द्वारा हटाए गए प्रत्येक तत्व के लिए है और उसके बाद इसे एक चर में सहेजें।

उदाहरण के लिए, यदि हमारे पास 5 संख्याओं के साथ "नमूना" (प्रकार int []) नामक एक सरणी है। हम 2 को हटाना चाहते हैं, इसलिए "Sample.Skip (2);" 2 नंबर के बिना एक ही सरणी वापस करना चाहिए।


क्या यह विधि केवल एक क्रम में तत्वों की एक निर्दिष्ट संख्या को पार नहीं करती है और फिर शेष तत्वों को वापस करती है ? आपके उदाहरण में आप जेनेरिक सूची के पहले दो तत्वों को "छोड़ेंगे" और न केवल 2 वें!
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();
} 

उदाहरण कोड मेरे ब्लॉग पर मिल सकते हैं , ट्रैकिंग करते रहें।


13
यह .ToArray()एक List<T>निर्माण और एक मौजूदा अनुक्रम लेने वाले निर्माता के अस्तित्व को देखते हुए हल्का पागल है ...
user7116
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.