एकल मान के साथ C # सरणी को कैसे पॉप्युलेट / इंप्रेट करें?


205

मुझे पता है कि C # में मूल्य प्रकारों की तात्कालिक सरणियों को स्वचालित रूप से प्रकार के डिफ़ॉल्ट मान (जैसे कि बूल के लिए गलत, इंट के लिए 0, आदि) के साथ आबादी है ।

वहाँ एक बीज मान के साथ किसी सरणी को ऑटो-पॉप्युलेट करने का एक तरीका है जो डिफ़ॉल्ट नहीं है? निर्माण पर या बाद में एक अंतर्निहित विधि (जैसे जावा की Arrays.fill () )? कहते हैं कि मैं एक बूलियन सरणी चाहता था जो झूठे के बजाय डिफ़ॉल्ट रूप से सच था। क्या ऐसा करने के लिए एक अंतर्निहित तरीका है, या क्या आपको बस लूप के लिए सरणी के माध्यम से पुनरावृत्त करना है?

 // Example pseudo-code:
 bool[] abValues = new[1000000];
 Array.Populate(abValues, true);

 // Currently how I'm handling this:
 bool[] abValues = new[1000000];
 for (int i = 0; i < 1000000; i++)
 {
     abValues[i] = true;
 }

सरणी के माध्यम से पुनरावृत्ति करने और "रीसेट" करने के लिए प्रत्येक मान सत्य को अप्रभावी लगता है। क्या इसके आसपास भी ऐसा है? हो सकता है कि सभी मानों को फ़्लिप करके?

इस प्रश्न को टाइप करने और इसके बारे में सोचने के बाद, मैं यह अनुमान लगा रहा हूं कि डिफ़ॉल्ट मान बस सी # दृश्यों के पीछे इन वस्तुओं के मेमोरी आवंटन को कैसे संभालते हैं, इसलिए मुझे लगता है कि ऐसा करना संभव नहीं है। लेकिन मैं अभी भी निश्चित रूप से जानना चाहता हूं!


मैं आमतौर पर is_found से is_still_hiding तक नाम बदलता हूं। हालांकि जवाब से प्यार है, मुझे एक टेस्ट केस में इंट की सरणी के लिए समान करने की आवश्यकता थी। (अच्छा प्रश्न)
ctrl-alt-delor-Novor

जवाबों:


146

एक फ्रेमवर्क विधि का पता नहीं है, लेकिन आप इसे करने के लिए एक त्वरित सहायक लिख सकते हैं।

public static void Populate<T>(this T[] arr, T value ) {
  for ( int i = 0; i < arr.Length;i++ ) {
    arr[i] = value;
  }
}

3
यदि आपको प्रतिलिपि की आवश्यकता नहीं है, तो मैं ++ के बजाय ++ को प्राथमिकता देता हूं।
void.pointer

24
i ++ प्रतियां i, वेतन वृद्धि i, और मूल मूल्य लौटाता है। ++ मैं सिर्फ बढ़ा हुआ मूल्य लौटाता हूं। इसलिए ++ i तेज़ है, जो कि बड़े लूप्स में महत्वपूर्ण हो सकता है, जैसे हम यहाँ बात कर रहे हैं।
तेनपन्न

57
@RobertDailey: यह एक संकलक अनुकूलन है, और अब सच नहीं है। मैंने सिर्फ अपने विश्वास को सत्यापित करने के लिए परीक्षण किया है: यदि i ++ का रिटर्न मान किसी भी चीज़ के लिए उपयोग नहीं किया जाता है, तो संकलक इसे आपके लिए स्वचालित रूप से ++ i के रूप में संकलित करेगा। इसके अलावा, यहां तक ​​कि जब मैं रिटर्न वैल्यू का उपयोग करता हूं, तो प्रदर्शन अंतर इतना छोटा होता है कि मुझे इसे मापने के लिए एक चरम मामला बनाने की आवश्यकता होती है। तब भी, यह केवल कुछ प्रतिशत अलग रनटाइम के परिणामस्वरूप था।
एडवर्ड नेड हार्वे

8
मैं इस तरह एक विस्तार विधि लिखा था लेकिन मैं इसे मूल सरणी लौटने था जैसे चेनिंग पद्धति के लिए अनुमति देने के लिए:int[] arr = new int[16].Populate(-1);
Gutblender

2
voidकरने के लिए बदलें T[]और फिर आप कर सकते हैंvar a = new int[100].Polupate(1)
orad

198
Enumerable.Repeat(true, 1000000).ToArray();

70
हालांकि यह काम करता है यह वास्तव में एक अच्छा समाधान नहीं है क्योंकि यह बहुत धीमा है; यह वास्तव में एक लूप के साथ चलने की तुलना में लगभग 4 गुना धीमा है।
patjbs

4
हाँ यह सच है, जब हम प्रदर्शन के लिए विचार करते हैं कि लूप तेज़ है
रॉनी

6
कुछ वास्तविक बेंचमार्क को देखने के लिए C # इनिशियलाइज़ एरे पर एक नज़र डालें ।
एकनोट

4
Enumerable.ToArrayगणना करने योग्य अनुक्रम के आकार को नहीं जानता है, इसलिए इसे सरणी आकार के रूप में अनुमान लगाना होगा। इसका मतलब है कि आपको हर बार ToArrayबफर आवंटित होने पर सरणी का आवंटन प्राप्त होगा , साथ ही ट्रिम के लिए अंत में एक और आवंटन। वहाँ भी भारी वस्तु के साथ शामिल उपरि है।
एडवर्ड ब्रे

5
बस एक नोट, कि संदर्भ प्रकारों के साथ यह पूरे सरणी को एक ही ऑब्जेक्ट के सभी संदर्भों के साथ भर देगा। यदि यह वह नहीं है जो आप चाहते हैं और आप वास्तव में प्रत्येक सरणी आइटम के लिए अलग-अलग ऑब्जेक्ट जनरेट करना चाहते हैं, तो stackoverflow.com/a/44937053/23715 देखें ।
एलेक्स चे

74

एक हजार trueमानों के साथ एक नई सरणी बनाएँ :

var items = Enumerable.Repeat<bool>(true, 1000).ToArray();  // Or ToList(), etc.

इसी तरह, आप पूर्णांक अनुक्रम उत्पन्न कर सकते हैं:

var items = Enumerable.Range(0, 1000).ToArray();  // 0..999

8
बुरा नहीं है, लेकिन यह अभी भी 4x के कारक के बारे में पाश के लिए की तुलना में धीमी है
patjbs

1
भविष्य में सिद्धांत में patjbs Enumerable.Repeat तेजी से प्रदर्शन करेगा क्योंकि यह एक समानांतर कार्यान्वयन का उपयोग करेगा।
पेटर पेत्रोव

1
@PetarPetrov कैश की किल्लत के कारण ऐसा कभी नहीं होगा। मुझे पूरा यकीन है कि सीपीयू कैश की प्रकृति के कारण, एकल सरणी पर समानांतर में काम करना हमेशा धीमा रहेगा, क्योंकि कंप्यूटर तुल्यकालिक काम की उम्मीद करता है और डेटा को उचित रूप से लोड करता है।
टर्नरी टॅपैररी

अपेक्षित निराशाकरण! = समय से पहले अनुकूलन की कमी।
डेनिस ग्लैडकी

24

बड़े सरणियों या सरणियों के लिए जो चर आकार होंगे जो आपको संभवतः उपयोग करना चाहिए:

Enumerable.Repeat(true, 1000000).ToArray();

छोटे सरणी के लिए आप C # 3 में संग्रह आरंभीकरण सिंटैक्स का उपयोग कर सकते हैं:

bool[] vals = new bool[]{ false, false, false, false, false, false, false };

संग्रह आरंभीकरण सिंटैक्स का लाभ यह है कि आपको प्रत्येक स्लॉट में समान मूल्य का उपयोग करने की आवश्यकता नहीं है और आप किसी स्लॉट को प्रारंभ करने के लिए अभिव्यक्ति या फ़ंक्शन का उपयोग कर सकते हैं। इसके अलावा, मुझे लगता है कि आप ऐरे स्लॉट को डिफ़ॉल्ट मान पर आरंभ करने की लागत से बचते हैं। इसलिए, उदाहरण के लिए:

bool[] vals = new bool[]{ false, true, false, !(a ||b) && c, SomeBoolMethod() };

और एक फ्लोट शुरू करने के लिए [] सरणी:float[] AlzCalDefault = new float[] {(float) 0.5, 18, 500, 1, 0};
जिम लाहमन

किसी सरणी का FWIW आरंभीकरण C # के किसी भी संस्करण में किया जा सकता है जैसे:bool[] vals = { false, true, false, !(a || b) && c, SomeBoolMethod() };
पीटर वैन डेर हाइजेन

24

यदि आपकी सरणी इतनी बड़ी है तो आपको BitArray का उपयोग करना चाहिए। यह बाइट के बजाय हर बूल के लिए 1 बिट का उपयोग करता है (जैसे बूल की एक सरणी में) आप बिट के साथ सही करने के लिए सभी बिट्स सेट कर सकते हैं। या सिर्फ सच पर आरंभ करें। यदि आपको इसे केवल एक बार करने की आवश्यकता है, तो यह केवल अधिक लागत होगी।

System.Collections.BitArray falses = new System.Collections.BitArray(100000, false);
System.Collections.BitArray trues = new System.Collections.BitArray(100000, true);

// Now both contain only true values.
falses.And(trues);

17

आप Array.Fill.NET कोर 2.0+ और .NET मानक 2.1+ में उपयोग कर सकते हैं ।


अति उत्कृष्ट! हालांकि इस बात से अवगत रहें कि यह एक अपेक्षाकृत नई विधि है। यह .NET कोर 2.0+ और .NET मानक 2.1 में उपलब्ध है, लेकिन विशेष रूप से .NET फ्रेमवर्क संस्करणों में से किसी में भी नहीं है। (यह .NET 5.0 में होगा, जो .NET फ्रेमवर्क और .NET कोर को एक साथ मिश्रित करता है)।
हाबिल

9

दुर्भाग्य से मुझे नहीं लगता कि कोई सीधा रास्ता है, लेकिन मुझे लगता है कि आप ऐसा करने के लिए सरणी वर्ग के लिए एक विस्तार विधि लिख सकते हैं

class Program
{
    static void Main(string[] args)
    {
        int[] arr = new int[1000];
        arr.Init(10);
        Array.ForEach(arr, Console.WriteLine);
    }
}

public static class ArrayExtensions
{
    public static void Init<T>(this T[] array, T defaultVaue)
    {
        if (array == null)
            return;
        for (int i = 0; i < array.Length; i++)
        {
            array[i] = defaultVaue;
        }
    }
}

मैं विस्तार के विचार को पसंद कर रहा हूं जितना अधिक मैं इसमें खुदाई करता हूं। कभी कभी अग्रिम और सरल समाधान वास्तव में सबसे अच्छा है!
patjbs

8

खैर थोड़ी और गुगली करने और पढ़ने के बाद मुझे यह पता चला:

bool[] bPrimes = new bool[1000000];
bPrimes = Array.ConvertAll<bool, bool>(bPrimes, b=> b=true);

जो निश्चित रूप से मैं देख रहा हूँ के करीब है। लेकिन मुझे यकीन नहीं है कि अगर यह फॉर-लूप में मूल सरणी के माध्यम से पुनरावृत्ति करने से बेहतर है और बस मूल्यों को बदल रहा है। वास्तव में एक त्वरित परीक्षण के बाद, यह लगभग 5. के कारक से धीमा प्रतीत होता है, तो वास्तव में एक अच्छा समाधान नहीं है!


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

हाँ, यह लूप के लिए बस एक काम की तरह लग रहा है और साथ ही साथ कुछ और भी काम करता है
15:48

यह एक नया सरणी बनाता है (मूल आवृत्ति नहीं बदलता है)।
जेपी स्टिग नीलसन

7

एक समानांतर कार्यान्वयन के बारे में क्या

public static void InitializeArray<T>(T[] array, T value)
{
    var cores = Environment.ProcessorCount;

    ArraySegment<T>[] segments = new ArraySegment<T>[cores];

    var step = array.Length / cores;
    for (int i = 0; i < cores; i++)
    {
        segments[i] = new ArraySegment<T>(array, i * step, step);
    }
    var remaining = array.Length % cores;
    if (remaining != 0)
    {
        var lastIndex = segments.Length - 1;
        segments[lastIndex] = new ArraySegment<T>(array, lastIndex * step, array.Length - (lastIndex * step));
    }

    var initializers = new Task[cores];
    for (int i = 0; i < cores; i++)
    {
        var index = i;
        var t = new Task(() =>
        {
            var s = segments[index];
            for (int j = 0; j < s.Count; j++)
            {
                array[j + s.Offset] = value;
            }
        });
        initializers[i] = t;
        t.Start();
    }

    Task.WaitAll(initializers);
}

जब केवल एक सरणी को आरम्भ करने से इस कोड की शक्ति को नहीं देखा जा सकता है, लेकिन मुझे लगता है कि आपको निश्चित रूप से "शुद्ध" के बारे में भूलना चाहिए।


यह झूठे बंटवारे के मुद्दे को जोखिम में डालता है, जिसमें विभिन्न धागे सीपीयू कैश लाइनों के लिए प्रतिस्पर्धा करते हैं और इसलिए एकल-थ्रेडेड कार्यान्वयन की तुलना में प्रदर्शन को कम करते हैं। चाहे ऐसा हो, प्रति-थ्रेड मेमोरी ब्लॉक और CPU आर्किटेक्चर के आकार पर निर्भर करता है।
एरिक जे।

7

नीचे दी गई कोड छोटी प्रतियों के लिए सरल पुनरावृत्ति को जोड़ती है और बड़ी प्रतियों के लिए Array.Copy

    public static void Populate<T>( T[] array, int startIndex, int count, T value ) {
        if ( array == null ) {
            throw new ArgumentNullException( "array" );
        }
        if ( (uint)startIndex >= array.Length ) {
            throw new ArgumentOutOfRangeException( "startIndex", "" );
        }
        if ( count < 0 || ( (uint)( startIndex + count ) > array.Length ) ) {
            throw new ArgumentOutOfRangeException( "count", "" );
        }
        const int Gap = 16;
        int i = startIndex;

        if ( count <= Gap * 2 ) {
            while ( count > 0 ) {
                array[ i ] = value;
                count--;
                i++;
            }
            return;
        }
        int aval = Gap;
        count -= Gap;

        do {
            array[ i ] = value;
            i++;
            --aval;
        } while ( aval > 0 );

        aval = Gap;
        while ( true ) {
            Array.Copy( array, startIndex, array, i, aval );
            i += aval;
            count -= aval;
            aval *= 2;
            if ( count <= aval ) {
                Array.Copy( array, startIndex, array, i, count );
                break;
            }
        }
    }

एक int [] सरणी का उपयोग करके विभिन्न सरणी लंबाई के लिए मानक हैं:

         2 Iterate:     1981 Populate:     2845
         4 Iterate:     2678 Populate:     3915
         8 Iterate:     4026 Populate:     6592
        16 Iterate:     6825 Populate:    10269
        32 Iterate:    16766 Populate:    18786
        64 Iterate:    27120 Populate:    35187
       128 Iterate:    49769 Populate:    53133
       256 Iterate:   100099 Populate:    71709
       512 Iterate:   184722 Populate:   107933
      1024 Iterate:   363727 Populate:   126389
      2048 Iterate:   710963 Populate:   220152
      4096 Iterate:  1419732 Populate:   291860
      8192 Iterate:  2854372 Populate:   685834
     16384 Iterate:  5703108 Populate:  1444185
     32768 Iterate: 11396999 Populate:  3210109

पहला कॉलम एक सरणी आकार है, जिसके बाद एक साधारण पुनरावृत्ति (@JaredPared कार्यान्वयन) का उपयोग करके कॉपी किया जाता है। इस विधि का समय उसके बाद है। ये चार पूर्णांक की संरचना की एक सरणी का उपयोग करने वाले बेंचमार्क हैं

         2 Iterate:     2473 Populate:     4589
         4 Iterate:     3966 Populate:     6081
         8 Iterate:     7326 Populate:     9050
        16 Iterate:    14606 Populate:    16114
        32 Iterate:    29170 Populate:    31473
        64 Iterate:    57117 Populate:    52079
       128 Iterate:   112927 Populate:    75503
       256 Iterate:   226767 Populate:   133276
       512 Iterate:   447424 Populate:   165912
      1024 Iterate:   890158 Populate:   367087
      2048 Iterate:  1786918 Populate:   492909
      4096 Iterate:  3570919 Populate:  1623861
      8192 Iterate:  7136554 Populate:  2857678
     16384 Iterate: 14258354 Populate:  6437759
     32768 Iterate: 28351852 Populate: 12843259

7

या ... आप उल्टे तर्क का इस्तेमाल कर सकते हैं। चलो falseमतलब trueऔर इसके विपरीत।

कोड नमूना

// bool[] isVisible = Enumerable.Repeat(true, 1000000).ToArray();
bool[] isHidden = new bool[1000000]; // Crazy-fast initialization!

// if (isVisible.All(v => v))
if (isHidden.All(v => !v))
{
    // Do stuff!
}

मजाकिया समाधान, हालांकि यह उदाहरण के लिए बहुत कठिन होगा क्योंकि आप 0. कम खो देते हैं
MrFox

1
यह वास्तव में एक व्यवहार्य विकल्प है यदि आप चर नाम पर "तर्क को उल्टा" करते हैं: bool[] isVisibleइसे बनाने के बजायbool[] isHidden
मार्कस ह्यूटर

1
लोगों को लगता है कि यह किसी तरह की फनी हैक है। यह एक सामान्य अनुकूलन तकनीक है। यदि आप भाग्यशाली हैं, तो कंपाइलर आपके लिए ऐसा करेगा।
l33t

4

यह भी काम करता है ... लेकिन अनावश्यक हो सकता है

 bool[] abValues = new bool[1000];
 abValues = abValues.Select( n => n = true ).ToArray<bool>();

4

यहाँ प्रस्तुत कई उत्तर एक लूप को उबालते हैं जो एक समय में एक तत्व को आरंभीकृत करता है, जो एक बार में मेमोरी के ब्लॉक पर संचालित करने के लिए डिज़ाइन किए गए सीपीयू निर्देशों का लाभ नहीं उठाता है।

.Net Standard 2.1 (इस लेखन के अनुसार पूर्वावलोकन में) Array.Fill ( ) प्रदान करता है , जो रनटाइम लाइब्रेरी में एक उच्च-प्रदर्शन कार्यान्वयन के लिए उधार देता है (हालांकि अब के रूप में, .NET कोर उस संभावना का लाभ नहीं उठाता है) ।

पहले वाले प्लेटफ़ॉर्म पर उन लोगों के लिए, निम्न विस्तार विधि एक मामूली अंतर द्वारा एक तुच्छ लूप को बेहतर बनाती है जब सरणी आकार महत्वपूर्ण होता है। मैंने इसे तब बनाया जब एक ऑनलाइन कोड चुनौती के लिए मेरा समाधान आवंटित समय बजट पर लगभग 20% था। इसने रनटाइम को लगभग 70% तक कम कर दिया। इस स्थिति में, सरणी भरण दूसरे लूप के अंदर किया गया था। BLOCK_SIZE को प्रयोग के बजाय आंत की भावना द्वारा निर्धारित किया गया था। कुछ अनुकूलन संभव हैं (जैसे पहले से तय ब्लॉक के बजाय वांछित मूल्य पर सेट सभी बाइट्स की प्रतिलिपि बनाना)।

internal const int BLOCK_SIZE = 256;
public static void Fill<T>(this T[] array, T value)
{
    if (array.Length < 2 * BLOCK_SIZE)
    {
        for (int i = 0; i < array.Length; i++) array[i] = value;
    }
    else
    {
        int fullBlocks = array.Length / BLOCK_SIZE;
        // Initialize first block
        for (int j = 0; j < BLOCK_SIZE; j++) array[j] = value;
        // Copy successive full blocks
        for (int blk = 1; blk < fullBlocks; blk++)
        {
            Array.Copy(array, 0, array, blk * BLOCK_SIZE, BLOCK_SIZE);
        }

        for (int rem = fullBlocks * BLOCK_SIZE; rem < array.Length; rem++)
        {
            array[rem] = value;
        }
    }
}

3

यदि आप सरणी में केवल कुछ मान सेट करने की योजना बना रहे हैं, लेकिन अधिकांश समय (कस्टम) डिफ़ॉल्ट मान प्राप्त करना चाहते हैं, तो आप कुछ इस तरह की कोशिश कर सकते हैं:

public class SparseArray<T>
{
    private Dictionary<int, T> values = new Dictionary<int, T>();

    private T defaultValue;

    public SparseArray(T defaultValue)
    {
        this.defaultValue = defaultValue;
    }

    public T this [int index]
    {
      set { values[index] = value; }
      get { return values.ContainsKey(index) ? values[index] ? defaultValue; }
    }
}

संभवतः आपको इसे उपयोगी बनाने के लिए अन्य इंटरफेस को लागू करने की आवश्यकता होगी, जैसे कि यह स्वयं सरणी पर ।


3

किसी भी ऑपरेशन को एकल ऑपरेशन के रूप में सभी तत्वों को सेट करने का कोई तरीका नहीं है, UNLESS, वह मान तत्व प्रकार डिफ़ॉल्ट मान है।

उदाहरण के लिए, यदि यह पूर्णांकों की एक सरणी है, तो आप उन सभी को एक ही ऑपरेशन के साथ शून्य पर सेट कर सकते हैं, जैसे: Array.Clear(...)


2

मुझे एहसास है कि मुझे पार्टी में देर हो रही है लेकिन यहाँ एक विचार है। एक रैपर लिखें जिसमें लिपटी हुई वैल्यू से और उसके लिए रूपांतरण ऑपरेटर हों ताकि इसे लिपटे हुए प्रकार के लिए स्टैंड-इन के रूप में इस्तेमाल किया जा सके। यह वास्तव में @ l33t से मूर्खतापूर्ण लगने वाले उत्तर से प्रेरित था।

सबसे पहले (C ++ से आने वाला) मुझे एहसास हुआ कि C # में किसी ऐरे के तत्वों के निर्माण के समय एक डिफॉल्ट ctor नहीं कहा जाता है। इसके बजाय - यहां तक ​​कि उपयोगकर्ता-परिभाषित डिफ़ॉल्ट निर्माणकर्ता की उपस्थिति में भी! - सभी सरणी तत्व शून्य-आरंभीकृत हैं। इसने मुझे चौंका दिया।

तो एक रैपर वर्ग जो वांछित मूल्य के साथ एक डिफ़ॉल्ट ctor प्रदान करता है, C ++ में सरणियों के लिए काम करेगा, लेकिन C # में नहीं। रूपांतरण पर वांछित बीज मान के लिए आवरण प्रकार के मानचित्र 0 को एक वर्कअराउंड देना है। इस तरह शून्य आरंभिक मूल्य सभी व्यावहारिक उद्देश्यों के लिए बीज के साथ आरंभ किए गए प्रतीत होते हैं:

public struct MyBool
{
    private bool _invertedValue;

    public MyBool(bool b) 
    {   
        _invertedValue = !b;
    }

    public static implicit operator MyBool(bool b)
    {
        return new MyBool(b);
    }

    public static implicit operator bool(MyBool mb)
    {
        return !mb._invertedValue;
    }

}

static void Main(string[] args)
{
        MyBool mb = false; // should expose false.
        Console.Out.WriteLine("false init gives false: " 
                              + !mb);

        MyBool[] fakeBoolArray = new MyBool[100];

        Console.Out.WriteLine("Default array elems are true: " 
                              + fakeBoolArray.All(b => b) );

        fakeBoolArray[21] = false;
        Console.Out.WriteLine("Assigning false worked: " 
                              + !fakeBoolArray[21]);

        fakeBoolArray[21] = true;
        // Should define ToString() on a MyBool,
        // hence the !! to force bool
        Console.Out.WriteLine("Assigning true again worked: " 
                              + !!fakeBoolArray[21]);
}

यह पैटर्न सभी मूल्य प्रकारों पर लागू होता है। उदाहरण के लिए 0 से 4 किलों के लिए मानचित्र यदि 4 के साथ आरंभीकरण वांछित था आदि।

मैं इसका एक टेम्पलेट बनाना पसंद करूंगा, जैसा कि C ++ में संभव होगा, टेम्पलेट मान के रूप में बीज मूल्य प्रदान करता है, लेकिन मैं समझता हूं कि यह C # में संभव नहीं है। या क्या मैं कुछ न कुछ भूल रहा हूं? (C ++ मैपिंग में बिल्कुल भी आवश्यक नहीं है क्योंकि कोई डिफ़ॉल्ट ctor प्रदान कर सकता है जिसे सरणी तत्वों के लिए कहा जाएगा।)

FWIW, यहाँ एक C ++ समकक्ष है: https://ideone.com/wG8yEh


2

यदि आप अपने तर्क को पलट सकते हैं तो आप Array.Clear()बूलियन सरणी को गलत पर सेट करने के लिए विधि का उपयोग कर सकते हैं ।

        int upperLimit = 21;
        double optimizeMe = Math.Sqrt(upperLimit);

        bool[] seiveContainer = new bool[upperLimit];
        Array.Clear(seiveContainer, 0, upperLimit);

2

यदि आप .NET कोर, .NET स्टैंडर्ड> = 2.1 पर हैं, या System.Memory पैकेज पर निर्भर हैं, तो आप Span<T>.Fill()विधि का उपयोग कर सकते हैं :

var valueToFill = 165;
var data = new int[100];

data.AsSpan().Fill(valueToFill);

// print array content
for (int i = 0; i < data.Length; i++)
{
    Console.WriteLine(data[i]);
}

https://dotnetfiddle.net/UsJ9bu


2

हमारे द्वारा Microsoft के लिए छोड़े गए फ्रेमवर्क उपयोगकर्ताओं के लिए एक और संस्करण यहां दिया गया है। यह पैनोसो थोफ के समाधान कीArray.Clear तुलना में 4 गुना तेज और तेज है और एरिक जे और पेटार पेत्रोव के समानांतर एक - बड़े सरणियों के लिए दो गुना तेज है।

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

public static void Fill<T> (T[] array, int count, T value, int threshold = 32)
{
    if (threshold <= 0)
        throw new ArgumentException("threshold");

    int current_size = 0, keep_looping_up_to = Math.Min(count, threshold);

    while (current_size < keep_looping_up_to)
        array[current_size++] = value;

    for (int at_least_half = (count + 1) >> 1; current_size < at_least_half; current_size <<= 1)
        Array.Copy(array, 0, array, current_size, current_size);

    Array.Copy(array, 0, array, current_size, count - current_size);
}

जैसा कि आप देख सकते हैं, यह पहले से ही आरंभिक हिस्से के दोहराए जाने पर आधारित है। यह सरल और कुशल है, लेकिन यह आधुनिक मेमोरी आर्किटेक्चर के लिए चलता है। इसलिए एक ऐसा संस्करण पैदा हुआ जो केवल कैश-फ्रेंडली सीड ब्लॉक बनाने के लिए दोहरीकरण का उपयोग करता है, जो तब लक्ष्य लक्ष्य पर चलने के लिए नष्ट हो जाता है:

const int ARRAY_COPY_THRESHOLD = 32;  // 16 ... 64 work equally well for all tested constellations
const int L1_CACHE_SIZE = 1 << 15;

public static void Fill<T> (T[] array, int count, T value, int element_size)
{
    int current_size = 0, keep_looping_up_to = Math.Min(count, ARRAY_COPY_THRESHOLD);

    while (current_size < keep_looping_up_to)
        array[current_size++] = value;

    int block_size = L1_CACHE_SIZE / element_size / 2;
    int keep_doubling_up_to = Math.Min(block_size, count >> 1);

    for ( ; current_size < keep_doubling_up_to; current_size <<= 1)
        Array.Copy(array, 0, array, current_size, current_size);

    for (int enough = count - block_size; current_size < enough; current_size += block_size)
        Array.Copy(array, 0, array, current_size, block_size);

    Array.Copy(array, 0, array, current_size, count - current_size);
}

नोट: (count + 1) >> 1अंतिम कोड दोहरीकरण लूप के लिए सीमा के रूप में आवश्यक है ताकि यह सुनिश्चित किया जा सके कि अंतिम कॉपी ऑपरेशन में शेष सभी को कवर करने के लिए पर्याप्त चारा है। इसके count >> 1बजाय यदि इसका उपयोग किया जाना हो तो यह अजीब बात नहीं है । वर्तमान संस्करण के लिए इसका कोई महत्व नहीं है क्योंकि लीनियर कॉपी लूप किसी भी सुस्त को उठाएगा।

एक सरणी सेल का आकार एक पैरामीटर के रूप में पारित किया जाना चाहिए क्योंकि - दिमाग चकराता है - जेनरिक का उपयोग करने की अनुमति नहीं है sizeofजब तक कि वे एक बाधा ( unmanaged) का उपयोग नहीं करते हैं जो भविष्य में उपलब्ध हो सकता है या नहीं हो सकता है। गलत अनुमान कोई बड़ी बात नहीं है, लेकिन प्रदर्शन सबसे अच्छा है यदि मूल्य सटीक है, तो निम्न कारणों से:

  • तत्व आकार को कम आंकने से आधे L1 कैश से अधिक आकार ब्लॉक हो सकते हैं, इसलिए प्रतिलिपि स्रोत डेटा की L1 से बेदखल होने और धीमी कैश स्तरों से फिर से प्राप्त होने की संभावना बढ़ जाती है।

  • सीपीयू के एल 1 कैश के अंडर-उपयोग में तत्व के आकार के परिणामों को कम करके, जिसका अर्थ है कि रैखिक ब्लॉक कॉपी लूप को अधिक से अधिक बार निष्पादित किया जाता है, यह इष्टतम उपयोग के साथ होगा। इस प्रकार, निश्चित लूप / कॉल ओवरहेड का अधिक कड़ाई से आवश्यक है।

यहाँ एक बेंचमार्क मेरे कोड के खिलाफ Array.Clearऔर अन्य तीन समाधानों का उल्लेख किया गया है। समय Int32[]दिए गए आकारों के पूर्णांक सरणियों ( ) को भरने के लिए हैं। कैश योनि आदि के कारण भिन्नता को कम करने के लिए, प्रत्येक परीक्षण को दो बार, बैक-टू-बैक निष्पादित किया गया था, और दूसरे निष्पादन के लिए समय लिया गया था।

array size   Array.Clear      Eric J.   Panos Theof  Petar Petrov   Darth Gizka
-------------------------------------------------------------------------------
     1000:       0,7 µs        0,2 µs        0,2 µs        6,8 µs       0,2 µs 
    10000:       8,0 µs        1,4 µs        1,2 µs        7,8 µs       0,9 µs 
   100000:      72,4 µs       12,4 µs        8,2 µs       33,6 µs       7,5 µs 
  1000000:     652,9 µs      135,8 µs      101,6 µs      197,7 µs      71,6 µs 
 10000000:    7182,6 µs     4174,9 µs     5193,3 µs     3691,5 µs    1658,1 µs 
100000000:   67142,3 µs    44853,3 µs    51372,5 µs    35195,5 µs   16585,1 µs 

क्या इस कोड का प्रदर्शन पर्याप्त नहीं होना चाहिए, तो एक होनहार एवेन्यू रैखिक कॉपी लूप (समान स्रोत ब्लॉक का उपयोग करने वाले सभी थ्रेड्स के साथ), या हमारे अच्छे पुराने दोस्त P / Invoke को समानांतर करेगा।

ध्यान दें: क्लीयरिंग और ब्लॉक्स को सामान्य रूप से रनटाइम रूटीन द्वारा किया जाता है जो कि MMX / SSE निर्देशों और व्हाट्सएप का उपयोग करते हुए अत्यधिक विशिष्ट कोड की शाखा होती है, इसलिए किसी भी सभ्य वातावरण में एक व्यक्ति संबंधित संबंधित नैतिक स्तर को समान रूप से कॉल करेगा std::memsetऔर पेशेवर प्रदर्शन स्तरों का आश्वासन दिया जाएगा। IOW, लाइब्रेरी फंक्शन द्वारा अधिकारों को Array.Clearहमारे सभी हाथ से लुढ़का हुआ संस्करण धूल में छोड़ देना चाहिए। तथ्य यह है कि यह चारों ओर का दूसरा रास्ता दिखाता है कि वास्तव में अजीब चीजें कितनी दूर हैं। वही Fill<>पहली बार किसी का रोल करने के लिए जाता है, क्योंकि यह अभी भी कोर और स्टैंडर्ड में ही है लेकिन फ्रेमवर्क में नहीं है। .NET को अभी लगभग बीस साल हो गए हैं और हमें अभी भी सबसे बुनियादी सामान के लिए P / Invoke को बाएं और दाएं करना है या अपना स्वयं का रोल करना है ...


1

इस पर कुछ और उत्तर हैं (डुप्लिकेट?) प्रश्न: सी # में मेमरी के बराबर क्या है?

किसी ने विकल्पों को निर्धारित किया है (वे एक असुरक्षित संस्करण शामिल करते हैं, लेकिन उन्होंने कोशिश नहीं की memset): http://techmikael.blogspot.co.uk/2009/12/filling-array-with-default-value.html


0

यहां एक और मूल्यांकन है System.Collections.BitArrayजिसके साथ इस तरह के एक निर्माता हैं।

bool[] result = new BitArray(1000000, true).Cast<bool>().ToArray();

या

bool[] result = new bool[1000000];
new BitArray(1000000, true).CopyTo(result, 0);

0

एक निजी वर्ग बनाएं जहाँ आप सरणी बनाते हैं और इसके लिए एक गेट्टर और सेटर है। जब तक आपको सरणी में प्रत्येक स्थिति की आवश्यकता न हो, तब तक कुछ अद्वितीय, जैसे यादृच्छिक, तब int का उपयोग करें? एक सरणी के रूप में और उसके बाद यदि स्थिति बराबर है तो उस स्थिति को रिक्त भरें और नया यादृच्छिक मान लौटाएं।

IsVisibleHandler
{

  private bool[] b = new bool[10000];

  public bool GetIsVisible(int x)
  {
  return !b[x]
  }

  public void SetIsVisibleTrueAt(int x)
  {
  b[x] = false //!true
  }
}

या उपयोग करें

public void SetIsVisibleAt(int x, bool isTrue)
{
b[x] = !isTrue;
}

सेटर के रूप में।


-2
Boolean[] data = new Boolean[25];

new Action<Boolean[]>((p) => { BitArray seed = new BitArray(p.Length, true); seed.CopyTo(p, 0); }).Invoke(data);

कृपया बेहतर फ़ॉर्मेटिंग और शायद कुछ समझाने वाले शब्दों का उपयोग करें ताकि दूसरे आपके समाधान को बेहतर ढंग से समझ सकें।
Gorgsenegger

1
आप लक्ष्य सरणी को विभाजित करके और विभिन्न विभाजनों के लिए बीज की नकल करके इनिशियलाइज़ेशन के प्रदर्शन को बढ़ाने के लिए इसका उपयोग कर सकते हैं। यह केवल एक विचार देने के लिए था - यह मेरा पहला है और यह मेरा आखिरी पोस्ट था।
ldsmithperrin
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.