2012-07-13 13 views
96

की छोटी सूचियों में एक सूची को विभाजित करें मैं सूची को छोटी सूचियों की एक श्रृंखला में विभाजित करने का प्रयास कर रहा हूं।एन आकार

मेरी समस्या: सूचियों को विभाजित करने के लिए मेरा कार्य उन्हें सही आकार की सूचियों में विभाजित नहीं करता है। इसे उन्हें आकार 30 की सूचियों में विभाजित करना चाहिए, बल्कि इसके बजाय उन्हें आकार 114 की सूचियों में विभाजित करना चाहिए?

मैं अपने फ़ंक्शन को आकार 30 या उससे कम की सूची की एक्स संख्या में एक सूची कैसे विभाजित कर सकता हूं?

public static List<List<float[]>> splitList(List <float[]> locations, int nSize=30) 
{  
    List<List<float[]>> list = new List<List<float[]>>(); 

    for (int i=(int)(Math.Ceiling((decimal)(locations.Count/nSize))); i>=0; i--) { 
     List <float[]> subLocat = new List <float[]>(locations); 

     if (subLocat.Count >= ((i*nSize)+nSize)) 
      subLocat.RemoveRange(i*nSize, nSize); 
     else subLocat.RemoveRange(i*nSize, subLocat.Count-(i*nSize)); 

     Debug.Log ("Index: "+i.ToString()+", Size: "+subLocat.Count.ToString()); 
     list.Add (subLocat); 
    } 

    return list; 
} 

अगर मैं आकार 144 की सूची पर फ़ंक्शन का उपयोग करें तो उत्पादन होता है:

सूचकांक: 4, आकार: 120
सूचकांक: 3, आकार: 114
सूचकांक: 2 , आकार: 114
सूचकांक: 1, आकार: 114
सूचकांक: 0, आकार: 114

+1

एक LINQ समाधान स्वीकार्य है, तो [इस सवाल का कुछ मदद की हो सकती है] (http://stackoverflow.com/questions/419019/split -List-में-उप-सूचियों-साथ-LINQ)। –

+0

विशेष रूप से सैम केसर के पिछले प्रश्न पर इसका जवाब। और जब तक यह एक स्कूल असाइनमेंट के लिए नहीं है, मैं बस उसके कोड का उपयोग और बंद करूँगा। – jcolebrand

उत्तर

110
public static List<List<float[]>> splitList(List<float[]> locations, int nSize=30) 
{   
    var list = new List<List<float[]>>(); 

    for (int i=0; i < locations.Count; i+= nSize) 
    { 
     list.Add(locations.GetRange(i, Math.Min(nSize, locations.Count - i))); 
    } 

    return list; 
} 

जेनेरिक संस्करण:

public static IEnumerable<List<T>> splitList<T>(List<T> locations, int nSize=30) 
{   
    for (int i=0; i < locations.Count; i+= nSize) 
    { 
     yield return locations.GetRange(i, Math.Min(nSize, locations.Count - i)); 
    } 
} 
+1

लवी 'उपज वापसी ' – lostmylogin

+0

तो यदि मेरे पास सूची लंबाई zillion है, और मैं छोटी सूचियों में विभाजित करना चाहता हूं लंबाई 30, और प्रत्येक छोटी सूची से मैं केवल (1) लेना चाहता हूं, फिर भी मैं 30 वस्तुओं की सूचियां बना सकता हूं जो मैंने 29 वस्तुओं को फेंक दिया। यह चालाक किया जा सकता है! –

24

तरीके के बारे में:

while(locations.Any()) 
{  
    list.Add(locations.Take(nSize).ToList()); 
    locations= locations.Skip(nSize).ToList(); 
} 
+0

क्या यह बहुत सारी स्मृति का उपभोग करने जा रहा है? प्रत्येक बार स्थान.Skip.ToList होता है मुझे आश्चर्य है कि अगर अधिक स्मृति आवंटित की जाती है और अकुशल आइटमों को एक नई सूची द्वारा संदर्भित किया जाता है। – Zasz

+0

हाँ प्रत्येक लूप पर नई सूची बनाई गई है। हाँ यह स्मृति का उपभोग करता है। लेकिन अगर आपको स्मृति समस्याएं हैं तो यह अनुकूलित करने की जगह नहीं है क्योंकि उस सूचियों के उदाहरण अगले लूप पर एकत्र किए जाने के लिए तैयार हैं। आप 'ToList' को छोड़कर स्मृति के लिए प्रदर्शन का व्यापार कर सकते हैं, लेकिन मैं इसे अनुकूलित करने की कोशिश नहीं करना चाहूंगा - यह बहुत छोटा है और असंभव रूप से एक बाधा है। इस कार्यान्वयन से मुख्य लाभ इसकी छोटीता है जिसे समझना आसान है। यदि आप चाहते हैं कि आप स्वीकृत उत्तर का उपयोग कर सकें तो यह उन सूचियों को नहीं बनाता है लेकिन यह थोड़ा अधिक जटिल है। – Rafal

+0

'.Skip (n) 'हर बार इसे' n' तत्वों पर पुनरावृत्त करता है, जबकि यह ठीक हो सकता है, प्रदर्शन-महत्वपूर्ण कोड के लिए विचार करना महत्वपूर्ण है। http://stackoverflow.com/questions/20002975/performance-of-skip-and-similar-functions-like-take – Chakrava

5

मैं एक सामान्य विधि है कि किसी भी प्रकार के ले जाएगा नाव शामिल है, और इसे इकाई परीक्षण हो गया है, आशा है कि यह मदद करता है:

/// <summary> 
    /// Breaks the list into groups with each group containing no more than the specified group size 
    /// </summary> 
    /// <typeparam name="T"></typeparam> 
    /// <param name="values">The values.</param> 
    /// <param name="groupSize">Size of the group.</param> 
    /// <returns></returns> 
    public static List<List<T>> SplitList<T>(IEnumerable<T> values, int groupSize, int? maxCount = null) 
    { 
     List<List<T>> result = new List<List<T>>(); 
     // Quick and special scenario 
     if (values.Count() <= groupSize) 
     { 
      result.Add(values.ToList()); 
     } 
     else 
     { 
      List<T> valueList = values.ToList(); 
      int startIndex = 0; 
      int count = valueList.Count; 
      int elementCount = 0; 

      while (startIndex < count && (!maxCount.HasValue || (maxCount.HasValue && startIndex < maxCount))) 
      { 
       elementCount = (startIndex + groupSize > count) ? count - startIndex : groupSize; 
       result.Add(valueList.GetRange(startIndex, elementCount)); 
       startIndex += elementCount; 
      } 
     } 


     return result; 
    } 
+0

धन्यवाद। आश्चर्य है कि क्या आप maxCount पैरामीटर परिभाषा के साथ टिप्पणियों को अद्यतन कर सकते हैं? एक सुरक्षा नेट? –

222

मैं निर्दिष्ट विस्तार प्रकार द्वारा उप-सूचियों में स्रोत सूची को खंडित करने के लिए इस विस्तार विधि का उपयोग करने का सुझाव दूंगा:

/// <summary> 
/// Helper methods for the lists. 
/// </summary> 
public static class ListExtensions 
{ 
    public static List<List<T>> ChunkBy<T>(this List<T> source, int chunkSize) 
    { 
     return source 
      .Select((x, i) => new { Index = i, Value = x }) 
      .GroupBy(x => x.Index/chunkSize) 
      .Select(x => x.Select(v => v.Value).ToList()) 
      .ToList(); 
    } 
} 

उदाहरण के लिए, यदि आप प्रति आइटम 5 आइटमों द्वारा 18 आइटमों की सूची को चकित करते हैं, तो यह आपको निम्न वस्तुओं के साथ 4 उपन्यासों की सूची देता है: 5-5-5-3।

+7

भयानक समाधान – MonsterMMORPG

+3

उत्पादन में इसका उपयोग करने से पहले, सुनिश्चित करें कि आप समझते हैं कि स्मृति और प्रदर्शन के लिए रन-टाइम प्रभाव क्या हैं। सिर्फ इसलिए कि LINQ संक्षिप्त हो सकता है, इसका मतलब यह नहीं है कि यह एक अच्छा विचार है। – Nick

+3

निश्चित रूप से, @ निक मैं कुछ भी करने से पहले सोचने के लिए सामान्य रूप से सुझाव दूंगा। LINQ के साथ छेड़छाड़ अक्सर बार-बार ऑपरेशन नहीं किया जाना चाहिए। आम तौर पर आपको बैच और/या समांतर में आइटम बैच को प्रोसेस करने के लिए सूचियों की सूची की आवश्यकता होती है। –

9

सर्ज-Tm समाधान, ठीक है भी इस सूची के लिए विस्तार विधि के रूप में जेनेरिक वर्जन (यह एक स्थिर वर्ग में डाल दिया) है:

public static List<List<T>> Split<T>(this List<T> items, int sliceSize = 30) 
{ 
    List<List<T>> list = new List<List<T>>(); 
    for (int i = 0; i < items.Count; i += sliceSize) 
     list.Add(items.GetRange(i, Math.Min(sliceSize, items.Count - i))); 
    return list; 
} 
6

मैं स्वीकार किए जाते हैं जवाब (सर्ज-Tm) सबसे मजबूत मिल जाए, लेकिन मैं एक सामान्य संस्करण का सुझाव देना चाहता हूं।

public static List<List<T>> splitList<T>(List<T> locations, int nSize = 30) 
    { 
     var list = new List<List<T>>(); 

     for (int i = 0; i < locations.Count; i += nSize) 
     { 
      list.Add(locations.GetRange(i, Math.Min(nSize, locations.Count - i))); 
     } 

     return list; 
    } 
1

लाइब्रेरी MoreLinq विधि कहा जाता है Batch

List<int> ids = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; // 10 elements 
int counter = 1; 
foreach(var batch in ids.Batch(2)) 
{ 
    foreach(var eachId in batch) 
    { 
     Console.WriteLine("Batch: {0}, Id: {1}", counter, eachId); 
    } 
    counter++; 
} 

परिणाम

Batch: 1, Id: 1 
Batch: 1, Id: 2 
Batch: 2, Id: 3 
Batch: 2, Id: 4 
Batch: 3, Id: 5 
Batch: 3, Id: 6 
Batch: 4, Id: 7 
Batch: 4, Id: 8 
Batch: 5, Id: 9 
Batch: 5, Id: 0 

ids 2 तत्वों के साथ 5 भागों में splitted रहे है।

+0

[ModeLinq] (https://morelinq.github.io/) के बारे में बताने के लिए धन्यवाद। यह एक अच्छी पुस्तकालय है। –

2

हालांकि अधिकांश समाधान काम कर सकते हैं, मुझे लगता है कि वे बहुत कुशलता से नहीं हैं। मान लीजिए कि क्या आप केवल पहले कुछ हिस्सों के पहले कुछ आइटम चाहते हैं। फिर आप अपने अनुक्रम में सभी (zillion) आइटमों को फिर से शुरू नहीं करना चाहेंगे।

निम्नलिखित दो बार अत्यधिक गणना करेंगे: एक बार लेने के लिए और एक बार छोड़ने के लिए। यह किसी भी अधिक तत्वों से अधिक की गणना नहीं होगा की तुलना में आप का उपयोग करेगा:

public static IEnumerable<IEnumerable<TSource>> ChunkBy<TSource> 
    (this IEnumerable<TSource> source, int chunkSize) 
{ 
    while (source.Any())      // while there are elements left 
    { // still something to chunk: 
     yield return source.Take(chunkSize); // return a chunk of chunkSize 
     source = source.Skip(chunkSize);  // skip the returned chunk 
    } 
} 
संबंधित मुद्दे