2011-02-02 12 views
9

मैं कई बाइट एरे बना रहा हूं जिन्हें एक बड़े बाइट सरणी बनाने के लिए एक साथ जुड़ने की आवश्यकता है - मैं बाइट [] के बिल्कुल उपयोग नहीं करना चाहूंगा लेकिन यहां कोई विकल्प नहीं है। ..बाइट की सूची # सी को सम्मिलित करना []

मैं प्रत्येक को एक सूची में जोड़ रहा हूं, जैसा कि मैंने उन्हें बनाया है, इसलिए मुझे केवल बाइट [] के बाद एक बार संयम करना होगा, लेकिन मेरा सवाल यह है कि वास्तव में सबसे अच्छा तरीका क्या है यह कर रहा हूं?

जब मेरे पास बाइट [] के अज्ञात संख्या के साथ एक सूची है और मैं उन्हें सभी को एक साथ जोड़ना चाहता हूं।

धन्यवाद।

उत्तर

18
listOfByteArrs.SelectMany(byteArr=>byteArr).ToArray() 

ऊपर कोड एक अनुक्रम में बाइट्स की दृश्यों के एक दृश्य को श्रेणीबद्ध - और एक सरणी में परिणाम की दुकान। नहीं तथ्य का इस्तेमाल कर रही है कि आप पहले से ही परिणामी बाइट सरणी की लंबाई को जानते हैं और इस प्रकार गतिशील बढ़ाया .ToArray() कार्यान्वयन जरूरी है कि एक से अधिक आवंटन शामिल है से बच सकते हैं और array- यह -

हालांकि पठनीय, यह अधिकतम कुशल है प्रतियां। इसके अलावा, SelectMany इटरेटर के संदर्भ में लागू किया गया है; इसका मतलब है बहुत सारे इंटरफ़ेस कॉल जो बहुत धीमी है। हालांकि, छोटे-आश डेटा-सेट आकारों के लिए यह मामला असंभव है।

हैं आप एक तेजी से कार्यान्वयन की जरूरत है तो आप निम्न कर सकते हैं:

var output = new byte[listOfByteArrs.Sum(arr=>arr.Length)]; 
int writeIdx=0; 
foreach(var byteArr in listOfByteArrs) { 
    byteArr.CopyTo(output, writeIdx); 
    writeIdx += byteArr.Length; 
} 

या Martinho पता चलता है के रूप में:

var output = new byte[listOfByteArrs.Sum(arr => arr.Length)]; 
using(var stream = new MemoryStream(output)) 
    foreach (var bytes in listOfByteArrs) 
     stream.Write(bytes, 0, bytes.Length); 

कुछ समय:

var listOfByteArrs = Enumerable.Range(1,1000) 
    .Select(i=>Enumerable.Range(0,i).Select(x=>(byte)x).ToArray()).ToList(); 

कम का उपयोग करना इन 500500 बाइट्स को संयोजित करने की विधि एफए का उपयोग करके 15 एमएमएस लेती है सेंट विधि मेरी मशीन पर 0.5 मिमी लेती है - वाईएमएमवी, और ध्यान दें कि कई अनुप्रयोगों के लिए दोनों पर्याप्त तेज़ से अधिक हैं ;-)।

अंत में, आप staticArray.Copy, निम्न स्तर के Buffer.BlockCopy, या एक वापस पूर्व आबंटित बफर के साथ एक MemoryStream साथ Array.CopyTo की जगह सकता है - इन सभी मेरी परीक्षण (64 .NET 4.0) पर काफी हूबहू प्रदर्शन करते हैं।

+4

हालांकि छोटे और स्पष्ट, ध्यान दें कि पारंपरिक समाधान की तुलना में यह कोड बहुत धीमा है। यदि यह काफी तेज़ है, तो बढ़िया है, लेकिन यह पर्याप्त तेज़ नहीं हो सकता है। –

+0

"पारंपरिक समाधान" कौन सा है? – amalgamate

+0

"परंपरागत" समाधान शायद मैनुअल होगा, लूप के लिए घोंसला। ब्लॉक-कॉपी आधारित समाधानों की तुलना में यह लगभग तीन गुना धीमा है, लेकिन अभी भी 'SelectMany' से 10 गुना तेज है। –

-1

hmm कैसे list.addrange?

+0

-1 के लिए कारण? – Fredou

+0

क्या AddRange एक सूची को बाइट में परिवर्तित करता है []? सं। –

2

उन्हें सभी को सूची के बजाय मेमोरीस्ट्रीम में लिखें। फिर MemoryStream.ToArray() को कॉल करें। या जब आपके पास सूची है, तो पहले सभी बाइट सरणी लंबाई को सारांशित करें, कुल लंबाई के साथ एक नया बाइट सरणी बनाएं, और अंतिम सरणी में अंतिम के बाद प्रत्येक सरणी की प्रतिलिपि बनाएँ।

0

बजाय एक List<byte[]> में प्रत्येक बाइट सरणी भंडारण की, आप के बजाय उन्हें सीधे एक List<byte> को जोड़ने, हर एक के लिए AddRange विधि का उपयोग कर सकता है।

1

उपयोग Linq:

List<byte[]> list = new List<byte[]>(); 
    list.Add(new byte[] { 1, 2, 3, 4 }); 
    list.Add(new byte[] { 1, 2, 3, 4 }); 
    list.Add(new byte[] { 1, 2, 3, 4 }); 

    IEnumerable<byte> result = Enumerable.Empty<byte>(); 

    foreach (byte[] bytes in list) 
    { 
     result = result.Concat(bytes); 
    } 

    byte[] newArray = result.ToArray(); 

हो सकता है कि तेजी से समाधान किया जाएगा (घोषित नहीं सरणी अग्रिम):

IEnumerable<byte> bytesEnumerable = GetBytesFromList(list); 

byte[] newArray = bytesEnumerable.ToArray(); 

private static IEnumerable<T> GetBytesFromList<T>(IEnumerable<IEnumerable<T>> list) 
{ 
    foreach (IEnumerable<T> elements in list) 
    { 
     foreach (T element in elements) 
     { 
      yield return element; 
     } 
    } 
} 

ऐसा लगता है ऊपर केवल एक बार प्रत्येक सरणी पुनरावृति की तरह।

+0

ऐसा लगता है कि यह धन्यवाद काम कर सकता है, मैं इसे जाने दूंगा। –

+2

ध्यान दें कि यह समाधान बाइट सरणी की संख्या में ओ (एन^2) है। (क्या आप देखते हैं क्यों? संकेत: अनुक्रम ऑपरेटर * आलसी * हैं।) आप उससे बेहतर कर सकते हैं। क्या आपको एक समाधान मिल सकता है जो बाइट एरे की संख्या में रैखिक है? –

+0

@Eric: धन्यवाद! यह मेरे लिए स्पष्ट नहीं था कि समाधान ओ (एन^2) है। अगर मैं बाइट्स के गणित बनाने के लिए अलग विधि का उपयोग करता हूं तो क्या होगा? मैंने जवाब अपडेट किया। –

4

यहां Andrew Bezzub और fejesjoco's answers पर आधारित समाधान है, जो सामने की सभी मेमोरी को पूर्व-आवंटित करता है। यह Θ (एन) स्मृति उपयोग और Θ (एन) समय उत्पन्न करता है (एन बाइट्स की कुल संख्या है)।

byte[] result = new byte[list.Sum(a => a.Length)]; 
using(var stream = new MemoryStream(result)) 
{ 
    foreach (byte[] bytes in list) 
    { 
     stream.Write(bytes, 0, bytes.Length); 
    } 
} 
return result;