9

更新:同様の質問があります


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 (列挙型ではなくテーブルが本当に必要なため、チャンクを修正しました。拡張メソッドを使用します。Jacob に感謝します):

最終的な実装:

チャンクを処理する拡張メソッド:

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

5 に答える 5

7

これは非常に読みやすく、シーケンスを 1 回だけ繰り返します。おそらく、繰り返される冗長な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;
}
于 2009-04-20T18:41:57.930 に答える
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));
    }
}
于 2009-09-26T17:31:05.683 に答える
0

ジェイコブは書いた

これは、チャンクで何を達成したいかにもよりますが、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;
}

このジェイコブに感謝します-私にとっては便利ですが、あなたの例のテストは <= ではなく <. < を使用し、行数がchunkSize未満の場合、ループには入りません。同様に、最後の部分的なチャンクはキャプチャされず、完全なチャンクのみがキャプチャされます。あなたが述べたように、例はテストされていないなどなので、他の誰かがあなたのコードをそのまま使用した場合の参考情報です;-)

于 2010-04-28T23:40:35.940 に答える