LINQ: Group a list of strings into chunks

LINQ: Group a list of strings into chunks, dividing the chunks by a whole-line marker (in the example "<Custom>")

public static partial class Queries
{
    public static IEnumerable<string[]> Execute(
        this IQueryHandler<DataChunker, IEnumerable<string[]>> handler,
        IEnumerable<string> data)
    {
        return handler.Execute(new DataChunker(data));
    }

    public class DataChunker : IQuery<IEnumerable<string[]>>
    {
        public DataChunker(IEnumerable<string> data)
        {
            this.Data = data;
        }

        public IEnumerable<string> Data { get; set; }
    }

    public static partial class Handlers
    {
        public sealed class CustomDataChunkerHandler : 
            IQueryHandler<DataChunker, IEnumerable<string[]>>
        {
            public const string LineBreak = "<Custom>";

            public IEnumerable<string[]> Execute(DataChunker query)
            {
                var enumerator = query.Data.GetEnumerator();

                while (enumerator.MoveNext())
                {
                    yield return NextChunk(enumerator).ToArray();
                }
            }

            private static IEnumerable<string> NextChunk(IEnumerator<string> enumerator)
            {
                do
                {
                    yield return enumerator.Current;
                }
                while (enumerator.MoveNext() && enumerator.Current != LineBreak);
            }
        }
    }
}
public class CustomDataChunkerHandlerTests
{
    [TestCase]
    public void Execute_WithNoData_ReturnsNothing()
    {
        var handler = new Queries.Handlers.CustomDataChunkerHandler();

        var result = handler.Execute(NoData)
            .ToArray();

        result.Length.Should().Be(0);
    }

    [TestCase]
    public void Execute_WithOneRowOfData_ReturnsOneRowOfData()
    {
        var handler = new Queries.Handlers.DepConDataChunkerHandler();

        var result = handler.Execute(OneRowOfData)
            .ToArray();

        result[0].Should().BeEquivalentTo("a");
    }

    [TestCase]
    public void Execute_WithOneChunkOfData_ReturnsOneRowOfData()
    {
        var handler = new Queries.Handlers.CustomDataChunkerHandler();

        var result = handler.Execute(OneChunkOfData)
            .ToArray();

        result[0].Should().BeEquivalentTo(new string[3] { "b", "c", "d" });
    }

    [TestCase]
    public void Execute_WithLotsOfData_ReturnsChunkedData()
    {
        var handler = new Queries.Handlers.CustomDataChunkerHandler();

        var result = handler.Execute(LotsOfData)
            .ToArray();

        result[0].Should().BeEquivalentTo(new string[3] { "f", "g", "h" });
        result[1].Should().BeEquivalentTo(new string[3] { "i", "j", "k" });
    }

    private static IEnumerable<string> NoData
    {
        get
        {
            return Enumerable.Empty<string>();
        }
    }

    private static IEnumerable<string> OneRowOfData
    {
        get
        {
            yield return "a";
        }
    }

    private static IEnumerable<string> OneChunkOfData
    {
        get
        {
            yield return "b";
            yield return "c";
            yield return "d";
        }
    }

    private static IEnumerable<string> LotsOfData
    {
        get
        {
            yield return "f";
            yield return "g";
            yield return "h";
            yield return Queries.Handlers.CustomDataChunkerHandler.LineBreak;
            yield return "i";
            yield return "j";
            yield return "k";
            yield return Queries.Handlers.CustomDataChunkerHandler.LineBreak;
        }
    }
}

Leave a Reply