2009-04-20 6 views
7

अद्यतन: यहाँ मैं कुछ हजार DataRows उस में के साथ एक DataTable एक similar questionलिंकटेक के साथ एक निश्चित आकार के भाग में डेटाटेबल को तोड़ने का एक साफ तरीका क्या है?


मान लीजिए है।

मैं प्रसंस्करण के लिए छोटी पंक्तियों के टुकड़ों में तालिका को तोड़ना चाहता हूं।

मैंने सोचा कि डेटा के साथ काम करने के लिए सी # 3 की बेहतर क्षमता मदद कर सकती है।

यह वह जगह है कंकाल मैं अब तक है:

DataTable Table = GetTonsOfData(); 

// Chunks should be any IEnumerable<Chunk> type 
var Chunks = ChunkifyTableIntoSmallerChunksSomehow; // ** help here! ** 

foreach(var Chunk in Chunks) 
{ 
    // Chunk should be any IEnumerable<DataRow> type 
    ProcessChunk(Chunk); 
} 

क्या ChunkifyTableIntoSmallerChunksSomehow बदलना चाहिए पर कोई सुझाव?

मुझे वास्तव में दिलचस्पी है कि कोई व्यक्ति सी # 3 टूल्स के साथ ऐसा कैसे करेगा। यदि इन उपकरणों को लागू करने का प्रयास अनुचित है, तो कृपया समझाएं!


अद्यतन 3 (बेडौल संशोधित रूप में मैं वास्तव में टेबल, नहीं ienumerables चाहते हैं, एक विस्तार विधि के साथ जा रहा - धन्यवाद याकूब):

अंतिम कार्यान्वयन: बेडौल संभाल करने

एक्सटेंशन विधि: कि विस्तार विधि का

public static class HarenExtensions 
{ 
    public static IEnumerable<DataTable> Chunkify(this DataTable table, int chunkSize) 
    { 
     for (int i = 0; i < table.Rows.Count; i += chunkSize) 
     { 
      DataTable Chunk = table.Clone(); 

      foreach (DataRow Row in table.Select().Skip(i).Take(chunkSize)) 
      { 
       Chunk.ImportRow(Row); 
      } 

      yield return Chunk; 
     } 
    } 
} 

उदाहरण उपभोक्ता, एक तदर्थ परीक्षण से नमूना उत्पादन के साथ:

class Program 
{ 
    static void Main(string[] args) 
    { 
     DataTable Table = GetTonsOfData(); 

     foreach (DataTable Chunk in Table.Chunkify(100)) 
     { 
      Console.WriteLine("{0} - {1}", Chunk.Rows[0][0], Chunk.Rows[Chunk.Rows.Count - 1][0]); 
     } 

     Console.ReadLine(); 
    } 

    static DataTable GetTonsOfData() 
    { 
     DataTable Table = new DataTable(); 
     Table.Columns.Add(new DataColumn()); 

     for (int i = 0; i < 1000; i++) 
     { 
      DataRow Row = Table.NewRow(); 
      Row[0] = i; 

      Table.Rows.Add(Row); 
     } 

     return Table; 
    } 
} 
+0

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

+0

आप उपर्युक्त एक विस्तार विधि बनाकर इसे रेखांकित कर सकते हैं। फिर आप var Chunks = तालिका में खंड से उपयोग कर सकते हैं। का चयन करें खंड का चयन करें; –

+0

मुझे यह विचार पसंद है, धन्यवाद –

उत्तर

6

यह लिंकिंग के साथ प्राप्त करने के लिए आप जो हासिल करना चाहते हैं उसके आधार पर यह लिंक के Skip और Take विधियों के लिए आदर्श उपयोग-केस जैसा लगता है। यह पूरी तरह से अनचाहे है, कभी भी आईडीई कोड में दर्ज नहीं किया गया है, लेकिन आपकी विधि इस तरह कुछ दिख सकती है।

private List<List<DataRow>> ChunkifyTable(DataTable table, int chunkSize) 
{ 
    List<List<DataRow>> chunks = new List<List<DaraRow>>(); 
    for (int i = 0; i < table.Rows.Count/chunkSize; i++) 
    { 
     chunks.Add(table.Rows.Skip(i * chunkSize).Take(chunkSize).ToList()); 
    } 

    return chunks; 
} 
+0

@Jacob: सुझाव के लिए धन्यवाद। मैंने यह रिटर्न टेबल बनाया और उपज कीवर्ड के साथ IENumerable लागू किया। जैसा कि आपने सुझाव दिया था, मैंने इसे एक विस्तार विधि में भी बदल दिया। बहुत अच्छा काम करता है! –

+0

मीठा! सुनकर खुशी हुई। –

+0

यह डेटासेट के लिए टूटा हुआ है जो 'chunkSize' द्वारा समान रूप से विभाजित नहीं है। 1/10 = 0 इनट्स का उपयोग करते समय, इसलिए तालिका का अंतिम भाग काट दिया जाता है। – mydogisbox

6

यह केवल अनुक्रम के माध्यम से दोहराता एक बार काफी पठनीय और है शायद आप बार-बार अनावश्यक Skip()/Take() कॉल की नहीं बल्कि खराब प्रदर्शन विशेषताओं की बचत:

public IEnumerable<IEnumerable<DataRow>> Chunkify(DataTable table, int size) 
{ 
    List<DataRow> chunk = new List<DataRow>(size); 

    foreach (var row in table.Rows) 
    { 
     chunk.Add(row); 
     if (chunk.Count == size) 
     { 
      yield return chunk; 
      chunk = new List<DataRow>(size); 
     } 
    } 

    if(chunk.Any()) yield return chunk; 
} 
+0

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

0

यहाँ एक दृष्टिकोण है कि काम दे सकता है:

public static class Extensions 
{ 
    public static IEnumerable<IEnumerable<T>> InPages<T>(this IEnumerable<T> enumOfT, int pageSize) 
    { 
     if (null == enumOfT) throw new ArgumentNullException("enumOfT"); 
     if (pageSize < 1) throw new ArgumentOutOfRangeException("pageSize"); 
     var enumerator = enumOfT.GetEnumerator(); 
     while (enumerator.MoveNext()) 
     { 
      yield return InPagesInternal(enumerator, pageSize); 
     } 
    } 
    private static IEnumerable<T> InPagesInternal<T>(IEnumerator<T> enumeratorOfT, int pageSize) 
    { 
     var count = 0; 
     while (true) 
     { 
      yield return enumeratorOfT.Current; 
      if (++count >= pageSize) yield break; 
      if (false == enumeratorOfT.MoveNext()) yield break; 
     } 
    } 
    public static string Join<T>(this IEnumerable<T> enumOfT, object separator) 
    { 
     var sb = new StringBuilder(); 
     if (enumOfT.Any()) 
     { 
      sb.Append(enumOfT.First()); 
      foreach (var item in enumOfT.Skip(1)) 
      { 
       sb.Append(separator).Append(item); 
      } 
     } 
     return sb.ToString(); 
    } 
} 
[TestFixture] 
public class Tests 
{ 
    [Test] 
    public void Test() 
    { 
     // Arrange 
     var ints = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 
     var expected = new[] 
     { 
      new[] { 1, 2, 3 }, 
      new[] { 4, 5, 6 }, 
      new[] { 7, 8, 9 }, 
      new[] { 10  }, 
     }; 

     // Act 
     var pages = ints.InPages(3); 

     // Assert 
     var expectedString = (from x in expected select x.Join(",")).Join(" ; "); 
     var pagesString = (from x in pages select x.Join(",")).Join(" ; "); 

     Console.WriteLine("Expected : " + expectedString); 
     Console.WriteLine("Pages : " + pagesString); 

     Assert.That(pagesString, Is.EqualTo(expectedString)); 
    } 
} 
0

याकूब ने लिखा

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

private List<List<DataRow>> ChunkifyTable(DataTable table, int chunkSize) 
{ 
    List<List<DataRow>> chunks = new List<List<DaraRow>>(); 
    for (int i = 0; i < table.Rows.Count/chunkSize; i++) 
    { 
     chunks.Add(table.Rows.Skip(i * chunkSize).Take(chunkSize).ToList()); 
    } 

    return chunks; 
} 

इस याकूब के लिए धन्यवाद - मेरे लिए उपयोगी है, लेकिन मुझे लगता है कि अपने उदाहरण में परीक्षण < = < नहीं होना चाहिए।यदि आप < का उपयोग करते हैं और पंक्तियों की संख्या से कम है तो chunkSize लूप कभी दर्ज नहीं किया जाता है। इसी तरह अंतिम आंशिक हिस्सा कब्जा नहीं किया जाता है, केवल पूर्ण भाग। जैसा कि आपने कहा है, उदाहरण अनचाहे है, इत्यादि। इसलिए यह सिर्फ एक एफवाईआई है यदि कोई अन्य आपके कोड वर्बैटिम का उपयोग करता है ;-)

संबंधित मुद्दे

 संबंधित मुद्दे