Skip to main content
 首页 » 编程设计

c#之LINQ 通过遍历字段数组来创建集合的替代方法

2024年01月28日25langtianya

我有一个数组,其中包含以下格式的数据结构字段;

[0] = Record 1 (Name Field) 
[1] = Record 1 (ID Field) 
[2] = Record 1 (Other Field) 
[3] = Record 2 (Name Field) 
[4] = Record 2 (ID Field) 
[5] = Record 2 (Other Field) 

等等

我正在将其处理成一个集合,如下所示;

for (int i = 0; i < components.Length; i = i + 3) 
{ 
    results.Add(new MyObj 
        { 
            Name = components[i], 
            Id = components[i + 1], 
            Other = components[i + 2], 
        }); 
} 

这工作正常,但我想知道是否有一种很好的方法可以使用 LINQ 实现相同的输出?这里没有功能需求,我只是好奇能不能做。

我确实做了一些按索引分组的实验(在 ToList() 数组之后);

var groupings = components 
    .GroupBy(x => components.IndexOf(x) / 3) 
    .Select(g => g.ToArray()) 
    .Select(a => new 
        { 
            Name = a[0], 
            Id = a[1], 
            Other = a[2] 
        }); 

这行得通,但我认为这对于我正在尝试做的事情来说有点矫枉过正。有没有更简单的方法来实现与 for 循环相同的输出?

请您参考如下方法:

看起来是乔什·爱因斯坦的 IEnumerable.Batch 的完美候选人扩大。它将可枚举的对象切成一定大小的 block ,并将它们作为数组的枚举提供:

public static IEnumerable<T[]> Batch<T>(this IEnumerable<T> self, int batchSize) 

在这个问题的情况下,你会做这样的事情:

var results =  
    from batch in components.Batch(3) 
    select new MyObj { Name = batch[0], Id = batch[1], Other = batch[2] }; 

更新:2 年过去了,我链接到的 Batch 扩展似乎已经消失了。由于它被认为是问题的答案,并且以防万一其他人发现它有用,这里是我当前对 Batch 的实现:

public static partial class EnumExts 
{ 
    /// <summary>Split sequence into blocks of specified size.</summary> 
    /// <typeparam name="T">Type of items in sequence</typeparam> 
    /// <param name="sequence"><see cref="IEnumerable{T}"/> sequence to split</param> 
    /// <param name="batchLength">Number of items per returned array</param> 
    /// <returns>Arrays of <paramref name="batchLength"/> items, with last array smaller if sequence count is not a multiple of <paramref name="batchLength"/></returns> 
    public static IEnumerable<T[]> Batch<T>(this IEnumerable<T> sequence, int batchLength) 
    { 
        if (sequence == null) 
            throw new ArgumentNullException("sequence"); 
        if (batchLength < 2) 
            throw new ArgumentException("Batch length must be at least 2", "batchLength"); 
 
        using (var iter = sequence.GetEnumerator()) 
        { 
            var bfr = new T[batchLength]; 
            while (true) 
            { 
                for (int i = 0; i < batchLength; i++) 
                { 
                    if (!iter.MoveNext()) 
                    { 
                        if (i == 0) 
                            yield break; 
                        Array.Resize(ref bfr, i); 
                        break; 
                    } 
 
                    bfr[i] = iter.Current; 
                } 
                yield return bfr; 
                bfr = new T[batchLength]; 
            } 
        } 
    } 
} 

此操作是延迟的、单一枚举并在线性时间内执行。与我见过的其他一些 Batch 实现相比,它相对较快,即使它为每个结果分配一个新数组也是如此。

这只是表明:在分析之前您永远无法分辨,并且您应该始终引用代码以防它消失。