如何从IEnumerable中剥离块

本文关键字:剥离 IEnumerable | 更新日期: 2023-09-27 18:13:20

我发布这篇文章更多的是作为一个学习练习,而不是因为我需要改变命令式循环的实现。我的问题是如何将这个循环转换为LINQ?给定一个输入IEnumerable字节,它被认为是在8字节的"块"中。输出的IEnumerable应该删除所有包含0的块。

粗略的命令式实现

    private static IEnumerable<byte> StripBlocksWithZeroes(IEnumerable<byte> input)
    {
        var stripped = new List<byte>();
        var inputArray = input.ToArray();
        for (int i = 0; i < inputArray.Length; i += 8)
        {
            if (inputArray[i + 0] != 0 &&
                inputArray[i + 1] != 0 &&
                inputArray[i + 2] != 0 &&
                inputArray[i + 3] != 0 &&
                inputArray[i + 4] != 0 &&
                inputArray[i + 5] != 0 &&
                inputArray[i + 6] != 0 &&
                inputArray[i + 7] != 0)
            {
                stripped.Add(inputArray[i + 0]);
                stripped.Add(inputArray[i + 1]);
                stripped.Add(inputArray[i + 2]);
                stripped.Add(inputArray[i + 3]);
                stripped.Add(inputArray[i + 4]);
                stripped.Add(inputArray[i + 5]);
                stripped.Add(inputArray[i + 6]);
                stripped.Add(inputArray[i + 7]);
            }
        }
        return stripped;
    }

如何从IEnumerable中剥离块

Off the top of my head:

inputArray.Select((item, index) => new {item, groupIndex = index / 8})
          .GroupBy(x => x.groupIndex)
          .Where(g => g.All(x => x.item != 0))
          //.Select(g => g.First().item)
          .SelectMany(g => g.Select(x => x.item))

说明:

利用整数除法,用一个groupIndex标记每一项,这样每个连续的8个组将有相同的groupIndex。

按群索引分组,所以现在我们有一个序列的序列。

对于每一个内序列,确保它不包含零。

将结果序列平放回单个序列

还有一个稍微不同的版本:

    return input.Select((value, index) => new { value, index })
                .GroupBy(x => x.index / 8, x => x.value)
                .Where(g => g.All(value => value != 0))
                .SelectMany(g => g);
注意:这段代码使用了这个GroupBy重载,它使用一个元素选择器来尽快摆脱索引。

您可以使用"整除技巧"按8个字节分组并检查其中是否有0:

private static IEnumerable<byte> StripBlocksWithZeroes(IEnumerable<byte> input)
{
    IEnumerable<byte> stripped = input
        .Select((b, i) => new { Byte = b, Index = i })
        .GroupBy(x => x.Index / 8)
        .Where(g => g.All(x => x.Byte != 0))
        .SelectMany(g => g.Select(x => x.Byte))
        .ToList();
    return stripped;
}