2009-04-20 54 views
7

更新:這裏有一個similar question用Linq將DataTable分成固定大小塊的乾淨方法是什麼?


假設我有一個DataTable在這幾千DataRows

我想分解成更小的行塊進行處理。

我認爲C#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有什麼建議?

我真的很感興趣的人如何做到這一點訪問C#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

我不使用這個分頁,但我只是實現了並行應用程序。如果您發現任何適用的重複項,請讓我知道,我會結束這個問題。 – 2009-04-20 17:54:47

+0

你可以通過創建一個擴展方法來完成上述操作。然後,你可以使用 VAR大塊大塊來自於= table.Chunkify 選擇塊; – 2009-04-20 18:17:08

+0

我喜歡這個主意,謝謝 – 2009-04-20 18:19:03

回答

6

對Linq的Skip和Take方法來說,這看起來是一個理想的用例,這取決於你想用分塊實現什麼。這是完全未經測試的,從未輸入IDE代碼,但您的方法可能看起來像這樣。

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; 
} 
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

這裏有一個方法可能工作:

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

雅各寫道

這似乎是一個理想的使用案例 Linq的跳過和採取方法, 取決於你想實現 與分塊。這完全是未經測試的 ,從未輸入IDE 代碼,但您的方法可能看起來像這樣的 。

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永遠不會進入循環。同樣,最後的部分塊不被捕獲,只有完整的塊。正如你所說,例如是未經檢驗的,所以等這僅僅是一個供參考的情況下,其他人使用你的代碼逐字;-)

相關問題