.NET一次遍历IEnumerable的几个元素

z4bn682m  于 2023-04-08  发布在  .NET
关注(0)|答案(6)|浏览(180)

给定一个集合,我需要一次遍历三个(或其他数量)元素。例如:

string[] exampleData = {"John", "Doe", "1.1.1990", "Jane", "Roe", "2.2.1980"}

for(int i = 0; i < exampleData.Length; i += 3) {
    CreateUser(foreName: exampleData[i], surName: exampleData[i+1], dateOfBirth: exampleData[i+2]);
}

如果exampleData是一个IEnumerable而不是一个数组,我怎么能有效地重现这个呢?

vtwuwzda

vtwuwzda1#

.NET 6及更高版本

您可以使用LINQ Chunk extension method

foreach (string[] chunk in exampleData.Chunk(3))
{
    CreateUser(foreName: chunk[0], surName: chunk[1], dateOfBirth: chunk[2]);
}

.NET 5及更早版本

你可以编写自己的扩展方法:

public static IEnumerable<IList<T>> ChunksOf<T>(this IEnumerable<T> sequence, int size)
{
    List<T> chunk = new List<T>(size);

    foreach (T element in sequence)
    {
        chunk.Add(element);
        if (chunk.Count == size)
        {
            yield return chunk;
            chunk = new List<T>(size);
        }
    }
}

这样称呼它:

foreach (IList<string> chunk in exampleData.ChunksOf(3))
{
    CreateUser(foreName: chunk[0], surName: chunk[1], dateOfBirth: chunk[2]);
}

请注意,如果sequence.Count()不是size的整数倍,则ChunksOf将丢弃最后一个部分块。如果您想返回一个部分块,则可以在末尾添加:if (chunk.Count > 0) yield return chunk;

doinxwow

doinxwow2#

此代码段将数组分组为3个元素的集合,然后为每个集合创建一个用户。

exampleData.Select((elem, index) => new {elem, index})
        .GroupBy(x => x.index/3)
        .Select(x => CreateUser(
                          x.ElementAt(0).elem,
                          x.ElementAt(1).elem,
                          x.ElementAt(2).elem));

当然,您需要确保数组的长度是3的倍数。

vohkndzv

vohkndzv3#

忘记foreach、花哨的linq、临时子列表等,回到根目录,怎么样?
在一次迭代中调用.GetEnumerator()和.MoveNext()三次。这就是枚举的核心。
前面的答案对我来说似乎过于复杂了。这是简单而核心的:-)。

8iwquhpp

8iwquhpp4#

虽然我更喜欢Michael的方法,但如果需要特定于字段的解析(例如DOB解析),您可能更喜欢更具体的方法

public static IEnumerable<User> ExtractUsers(IEnumerable<string> input)
{
    int i = 0;
    string forename;
    string surname;
    string dateofbirth;
    foreach (string current in input) 
    {
        switch (i) 
        {
        case 0:
            one = forename;
            break;
        case 1:
            two = surname;
            break;
        case 2:
            three = dateofbirth;
            i = -1; //uck, this will get incremented at the bottom
            yield return CreateUser(forename, surname, dateofbirth);
            break;
        }
        i++;
    }
}
8cdiaqws

8cdiaqws5#

Take()Skip()可以做你想做的事情,但我建议你避免像这样使用数组。你最好创建一个Person类,其中包含FirstNameLastNameDateOfBirth属性,并保留一个这些属性的数组。

t5fffqht

t5fffqht6#

可以使用LINQ

string[] exampleData = {"John", "Doe", "1.1.1990", "Jane", "Roe", "2.2.1980"};

        int chunkSize = 3;
        var seqences = from seqIndex in Enumerable.Range(0, exampleData.Length)
                       group exampleData[seqIndex] by seqIndex / chunkSize;
        foreach (var sub in seqences)
        {
            CreateUser(sub.ToList()[0], sub.ToList()[1], sub.ToList()[2]);
        }

编辑:

var seqences = from m in Enumerable.Range(0, exampleData.Count()) group 
                           exampleData.ToList()[m] by m / chunkSize;

int chunkSize = 3;
        var seqences = Enumerable.Range(0, exampleData.Count())
                       .GroupBy(m => m/chunkSize, m => exampleData.ToList()[m]);

相关问题