ArraySegment <T> वर्ग का उपयोग क्या है?


97

मैं कक्षा में ArraySegment<byte>उपवर्ग करते हुए टाइप में आया था MessageEncoder

अब मैं समझता हूं कि यह किसी दिए गए ऐरे का एक सेगमेंट है, एक ऑफसेट लेता है, कोई गणना योग्य नहीं है, और इसमें इंडेक्सर नहीं है, लेकिन मैं अभी भी इसके उपयोग को समझने में विफल हूं। क्या कोई उदाहरण के साथ समझा सकता है?


8
ऐसा लग रहा है कि ArraySegment.Net 4.5 में दमदार है।
18

इस सवाल की तरह प्रयास करने के लिए ..
केन

जवाबों:


55

ArraySegment<T>.NET 4.5 + और .NET कोर में बहुत अधिक उपयोगी हो गया है क्योंकि यह अब लागू होता है:

  • IList<T>
  • ICollection<T>
  • IEnumerable<T>
  • IEnumerable
  • IReadOnlyList<T>
  • IReadOnlyCollection<T>

.NET 4 संस्करण के विपरीत जिसने कोई भी इंटरफेस लागू नहीं किया।

वर्ग अब LINQ की अद्भुत दुनिया में भाग लेने में सक्षम है, इसलिए हम सामान्य LINQ चीजें कर सकते हैं जैसे कि सामग्री को क्वेरी करें, मूल सरणी को प्रभावित किए बिना सामग्री को उलट दें, पहला आइटम प्राप्त करें, और इसी तरह:

var array = new byte[] { 5, 8, 9, 20, 70, 44, 2, 4 };
array.Dump();
var segment = new ArraySegment<byte>(array, 2, 3);
segment.Dump(); // output: 9, 20, 70
segment.Reverse().Dump(); // output 70, 20, 9
segment.Any(s => s == 99).Dump(); // output false
segment.First().Dump(); // output 9
array.Dump(); // no change

4
हालाँकि वे बेवजह GetEnumeratorनिजी बना है , जिसका अर्थ है कि आप IEnumerable<T>इसे कॉल करने के लिए (एक बॉक्सिंग रूपांतरण) करने के लिए मजबूर हैं । ओह!
ब्लूराजा - डैनी पफ्लुगुएफ्ट

27
  1. IO कक्षाओं के लिए बफरिंग - एक साथ पढ़ने और लिखने के संचालन के लिए एक ही बफर का उपयोग करें और एक एकल संरचना है जिसे आप अपने पूरे ऑपरेशन के बारे में बता सकते हैं।
  2. फ़ंक्शंस सेट करें - गणितीय रूप से बोलते हुए आप इस नई संरचना का उपयोग करके किसी भी सन्निहित उप-भाग का प्रतिनिधित्व कर सकते हैं। मूल रूप से इसका मतलब है कि आप ऐरे के विभाजन बना सकते हैं, लेकिन आप सभी बाधाओं और सभी बुराइयों का प्रतिनिधित्व नहीं कर सकते। ध्यान दें कि The1 द्वारा प्रस्तावित फोन टीज़र को ArraySegment विभाजन और एक ट्री संरचना का उपयोग करके सुरुचिपूर्ण ढंग से हल किया जा सकता था। पहले पेड़ की गहराई का पता लगाकर अंतिम संख्या लिखी जा सकती थी। मुझे लगता है कि स्मृति और गति के मामले में यह एक आदर्श परिदृश्य रहा होगा।
  3. मल्टीथ्रेडिंग - अब आप नियंत्रण द्वार के रूप में खंडित सरणियों का उपयोग करते हुए एक ही डेटा स्रोत पर काम करने के लिए कई थ्रेड्स को स्पॉन कर सकते हैं। लूप जो असतत गणना का उपयोग करते हैं, उन्हें अब बहुत आसानी से खेती की जा सकती है, कुछ ऐसा जो नवीनतम C ++ कंपाइलर कोड अनुकूलन कदम के रूप में करने लगे हैं।
  4. UI विभाजन - खंडित संरचनाओं का उपयोग करके अपने UI को प्रदर्शित करता है। अब आप संरचनाओं के डेटा का प्रतिनिधित्व करने वाली संरचनाओं को संग्रहीत कर सकते हैं जो जल्दी से प्रदर्शन कार्यों पर लागू हो सकते हैं। एकल सन्निहित सरणियों का उपयोग असतत विचारों को प्रदर्शित करने के लिए किया जा सकता है, या यहां तक ​​कि एक पदानुक्रम में नोड्स जैसे ट्री व्यू में नोड डेटा संग्रह खंडों में खंडित करके ट्री व्यू में प्रदर्शित किया जा सकता है।

इस उदाहरण में, हम यह देखते हैं कि आप मूल सरणी, ऑफसेट और गणना गुणों का उपयोग कैसे कर सकते हैं, और यह भी कि आप ArraySegment में निर्दिष्ट तत्वों के माध्यम से कैसे लूप कर सकते हैं।

using System;

class Program
{
    static void Main()
    {
        // Create an ArraySegment from this array.
        int[] array = { 10, 20, 30 };
        ArraySegment<int> segment = new ArraySegment<int>(array, 1, 2);

        // Write the array.
        Console.WriteLine("-- Array --");
        int[] original = segment.Array;
        foreach (int value in original)
        {
            Console.WriteLine(value);
        }

        // Write the offset.
        Console.WriteLine("-- Offset --");
        Console.WriteLine(segment.Offset);

        // Write the count.
        Console.WriteLine("-- Count --");
        Console.WriteLine(segment.Count);

        // Write the elements in the range specified in the ArraySegment.
        Console.WriteLine("-- Range --");
        for (int i = segment.Offset; i < segment.Count+segment.Offset; i++)
        {
            Console.WriteLine(segment.Array[i]);
        }
    }
}

सरणी संरचना - वे क्या सोच रहे थे?


3
ArraySegment सिर्फ एक संरचना है। मेरा सबसे अच्छा अनुमान यह है कि इसका उद्देश्य यह है कि किसी खंड के खंड को बिना उसकी प्रतिलिपि बनाए बिना पास कर दिया जाए।
ब्रायन

1
मेरा मानना ​​है कि लूप के लिए स्टेटमेंट स्टेटमेंट होना चाहिए i < segment.Offset + segment.Count
एरेन एर्सोन्मेज़

1
आपके द्वारा उल्लिखित तथ्यों के लिए +1 लेकिन @ सही है: आप उस तरह के खंड के तत्वों को पुनरावृत्त नहीं कर सकते।
फाक गेर

3
जब आप किसी व्यक्ति के कोड का उपयोग करते हैं, तो यह आमतौर पर अटेंशन देने के लिए उपयुक्त होता है। यह सिर्फ अच्छा शिष्टाचार है। आपका उदाहरण dotnetperls.com/arraysegment से उत्पन्न हुआ है ।

1
जब तक, निश्चित रूप से, उन्होंने इसे आपके उत्तर से उधार लिया था। किस स्थिति में, उन्हें आपको क्रेडिट देना चाहिए। :)

26

यह एक छोटा सा सिपाही है जो कुछ भी नहीं करता है लेकिन एक सरणी के संदर्भ में रखता है और एक इंडेक्स रेंज को संग्रहीत करता है। थोड़ा खतरनाक, सावधान रहें कि यह सरणी डेटा की प्रतिलिपि नहीं बनाता है और किसी भी तरह से सरणी को अपरिवर्तनीय नहीं बनाता है या अपरिवर्तनीयता की आवश्यकता व्यक्त नहीं करता है। अधिक विशिष्ट प्रोग्रामिंग पैटर्न सरणी और एक लंबाई चर या पैरामीटर को बस रखने या पास करने के लिए है, जैसे कि यह .NET BeginRead () विधियों, String.SubString (), Encoding.GetString (), आदि, आदि में किया जाता है।

यह .NET फ्रेमवर्क के अंदर बहुत अधिक उपयोग नहीं करता है, सिवाय इसके कि एक विशेष Microsoft प्रोग्रामर की तरह क्या लगता है जो वेब सॉकेट और WCF पर काम करता है। जो शायद उचित मार्गदर्शन है, यदि आप इसे पसंद करते हैं तो इसका उपयोग करें। यह .NET 4.6 में एक पीक-ए-बू किया था, जोड़ा MemoryStream.TryGetBuffer () विधि का उपयोग करता है। दो होने पर प्राथमिकता दीoutमैं मानने तर्क प्राथमिकता देता हूं।

सामान्य तौर पर, स्लाइस की अधिक सार्वभौमिक धारणा प्रिंसिपल .NET इंजीनियरों की इच्छा सूची में उच्च होती है, जैसे मैड्स टॉर्गेसेन और स्टीफन नोबल। उत्तरार्द्ध ने array[:]कुछ समय पहले वाक्यविन्यास प्रस्ताव को छोड़ दिया था, आप देख सकते हैं कि वे इस रोसलिन पृष्ठ के बारे में क्या सोच रहे हैं । मुझे लगता है कि CLR समर्थन मिल रहा है कि यह अंततः क्या टिका है। यह सक्रिय रूप से C # संस्करण 7 afaik के लिए सोचा जा रहा है, System.Slices पर अपनी नज़र बनाए रखें

अद्यतन: मृत लिंक, यह स्पैन के रूप में संस्करण 7.2 में भेज दिया गया है ।

Update2: रेंज और इंडेक्स प्रकार और एक स्लाइस () विधि के साथ C # संस्करण 8.0 में अधिक समर्थन।


"यह बहुत उपयोगी नहीं है '- मैं यह अविश्वसनीय रूप से एक प्रणाली में उपयोगी है कि दुर्भाग्य से स्मृति सीमा के कारण सूक्ष्म अनुकूलन के लिए आवश्यक पाया तथ्य देखते हैं कि। भी अन्य" करता है इसकी उपयोगिता भंग करने नहीं ठेठ "समाधान
AaronHS

5
ठीक है, ठीक है, मुझे वास्तव में हर किसी से एक प्रशंसा की आवश्यकता नहीं है जो इसे इस्तेमाल करने की आदत में मिला है :) @ CRice की टिप्पणी को बढ़ाने के लिए सर्वश्रेष्ठ। जैसा कि कहा गया है, "यदि आप इसे पसंद करते हैं तो इसका उपयोग करें"। इसलिए इसका उपयोग करें। स्लाइस भयानक होगा, इंतजार नहीं कर सकता।
हंस पासंत

वहाँ उन अपरिवर्तनीय शुद्धतावादियों के लिए एक ReadOnlySpan है।
अरेक बाल

7

एक आवरण वर्ग के बारे में क्या है? बस अस्थायी बफ़र्स को कॉपी डेटा से बचने के लिए।

public class SubArray<T> {
        private ArraySegment<T> segment;

        public SubArray(T[] array, int offset, int count) {
            segment = new ArraySegment<T>(array, offset, count);
        }
        public int Count {
            get { return segment.Count; }
        }

        public T this[int index] {
            get {
               return segment.Array[segment.Offset + index];
            }
        }

        public T[] ToArray() {
            T[] temp = new T[segment.Count];
            Array.Copy(segment.Array, segment.Offset, temp, 0, segment.Count);
            return temp;
        }

        public IEnumerator<T> GetEnumerator() {
            for (int i = segment.Offset; i < segment.Offset + segment.Count; i++) {
                yield return segment.Array[i];
            }
        }
    } //end of the class

उदाहरण:

byte[] pp = new byte[] { 1, 2, 3, 4 };
SubArray<byte> sa = new SubArray<byte>(pp, 2, 2);

Console.WriteLine(sa[0]);
Console.WriteLine(sa[1]);
//Console.WriteLine(b[2]); exception

Console.WriteLine();
foreach (byte b in sa) {
    Console.WriteLine(b);
}

ouput:

3
4

3
4

बहुत उपयोगी दोस्त, धन्यवाद, ध्यान दें कि आप इसे लागू कर सकते हैं IEnumerable<T>तो IEnumerator जोड़ सकते हैंIEnumerable.GetEnumerator() { return GetEnumerator(); }
MaYaN

5

ArraySegment आपके विचार से अधिक उपयोगी है। निम्नलिखित इकाई परीक्षण चलाने की कोशिश करें और चकित होने के लिए तैयार रहें!

    [TestMethod]
    public void ArraySegmentMagic()
    {
        var arr = new[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

        var arrSegs = new ArraySegment<int>[3];
        arrSegs[0] = new ArraySegment<int>(arr, 0, 3);
        arrSegs[1] = new ArraySegment<int>(arr, 3, 3);
        arrSegs[2] = new ArraySegment<int>(arr, 6, 3);
        for (var i = 0; i < 3; i++)
        {
            var seg = arrSegs[i] as IList<int>;
            Console.Write(seg.GetType().Name.Substring(0, 12) + i);
            Console.Write(" {");
            for (var j = 0; j < seg.Count; j++)
            {
                Console.Write("{0},", seg[j]);
            }
            Console.WriteLine("}");
        }
    }

आप देखिए, आपको जो करना है, उसे IList को ArraySegment देना है और यह उन सभी चीजों को करेगा जो आप शायद पहली जगह में करने की उम्मीद करते हैं। ध्यान दें कि प्रकार अभी भी ArraySegment है, भले ही यह एक सामान्य सूची की तरह व्यवहार कर रहा हो।

उत्पादन:

ArraySegment0 {0,1,2,}
ArraySegment1 {3,4,5,}
ArraySegment2 {6,7,8,}

4
यह इसे करने के लिए कास्ट करने के लिए आवश्यक है दया आती है IList<T>। मुझे उम्मीद है कि इंडेक्सर होगा public
xmedeko

2
जो कोई भी इस उत्तर पर आता है और इसके चमत्कार समाधान के बारे में सोचता है, मैं पहले सरणी के खंड से सूचकांक बाधाओं का उपयोग करके मूल सरणी तक सीधे पहुंच की तुलना में आपकी प्रदर्शन आवश्यकताओं और बेंचमार्क पर विचार करने की सलाह देता हूं। IList के लिए कास्टिंग को कार्यान्वयन के पहले IList इंटरफ़ेस के माध्यम से कूदने के लिए अनुक्रमणिका (अनुक्रमणिका सहित) की आवश्यकता होती है। इंटरनेट पर बहुत सारी चर्चाएं हैं जहां लोग तंग छोरों में अमूर्त कॉल का उपयोग करने की प्रदर्शन लागत के बारे में बात करते हैं। यहां पढ़ें: github.com/dotnet/coreclr/issues/9105
JamesHoux

3

सरल शब्दों में: यह एक सरणी का संदर्भ रखता है, जिससे आपको एकल सरणी चर के लिए कई संदर्भ मिल सकते हैं, प्रत्येक एक अलग श्रेणी के साथ।

वास्तव में यह आपको अनुक्रमणिका और लंबाई धारण करने के लिए, कई चर रखने के बजाय, अधिक संरचित तरीके से एक सरणी के वर्गों का उपयोग करने और पास करने में मदद करता है। यह भी सरणी वर्गों के साथ और अधिक आसानी से काम करने के लिए संग्रह इंटरफेस प्रदान करता है।

उदाहरण के लिए निम्नलिखित दो कोड उदाहरण एक ही काम करते हैं, एक ArraySegment के साथ और एक बिना:

        byte[] arr1 = new byte[] { 1, 2, 3, 4, 5, 6 };
        ArraySegment<byte> seg1 = new ArraySegment<byte>(arr1, 2, 2);
        MessageBox.Show((seg1 as IList<byte>)[0].ToString());

तथा,

        byte[] arr1 = new byte[] { 1, 2, 3, 4, 5, 6 };
        int offset = 2;
        int length = 2;
        byte[] arr2 = arr1;
        MessageBox.Show(arr2[offset + 0].ToString());

स्पष्ट रूप से पहला कोड स्निपेट अधिक पसंद किया जाता है, विशेष रूप से जब आप किसी फ़ंक्शन में सरणी सेगमेंट पास करना चाहते हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.