如何将IEnumerable中的每两项作为一对?

Neb*_*ron 4 c# ienumerable tuples list

IEnumerable<string>看起来像{"First", "1", "Second", "2", ... }.

我需要遍历列表并创建IEnumerable<Tuple<string, string>>Tuples的外观:

"First", "1"

"Second", "2"
Run Code Online (Sandbox Code Playgroud)

所以我需要从列表中创建对,我必须得到如上所述的对.

eul*_*rfx 12

实现此目的的延迟扩展方法是:

public static IEnumerable<Tuple<T, T>> Tupelize<T>(this IEnumerable<T> source)
{
    using (var enumerator = source.GetEnumerator())
        while (enumerator.MoveNext())
        {
            var item1 = enumerator.Current;

            if (!enumerator.MoveNext())
                throw new ArgumentException();

            var item2 = enumerator.Current;

            yield return new Tuple<T, T>(item1, item2);
        }
}
Run Code Online (Sandbox Code Playgroud)

请注意,如果元素的数量碰巧不均匀,则会抛出.另一种方法是使用此扩展方法将源集合拆分为2的块:

public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> list, int batchSize)
{

    var batch = new List<T>(batchSize);

    foreach (var item in list)
    {
        batch.Add(item);
        if (batch.Count == batchSize)
        {
            yield return batch;
            batch = new List<T>(batchSize);
        }
    }

    if (batch.Count > 0)
        yield return batch;
}
Run Code Online (Sandbox Code Playgroud)

然后你可以这样做:

var tuples = items.Chunk(2)
    .Select(x => new Tuple<string, string>(x.First(), x.Skip(1).First()))
    .ToArray();
Run Code Online (Sandbox Code Playgroud)

最后,仅使用现有的扩展方法:

var tuples = items.Where((x, i) => i % 2 == 0)
    .Zip(items.Where((x, i) => i % 2 == 1), 
                     (a, b) => new Tuple<string, string>(a, b))
    .ToArray();
Run Code Online (Sandbox Code Playgroud)


dev*_*tal 5

morelinq包含批量扩展方法,可以执行您想要的操作:

var str = new string[] { "First", "1", "Second", "2", "Third", "3" };
var tuples = str.Batch(2, r => new Tuple<string, string>(r.FirstOrDefault(), r.LastOrDefault()));
Run Code Online (Sandbox Code Playgroud)


adr*_*nks 5

可以这样做:

var pairs = source.Select((value, index) => new {Index = index, Value = value})
                  .GroupBy(x => x.Index / 2)
                  .Select(g => new Tuple<string, string>(g.ElementAt(0).Value, 
                                                         g.ElementAt(1).Value));
Run Code Online (Sandbox Code Playgroud)

这会给你一个IEnumerable<Tuple<string, string>>. 它的工作原理是按元素的奇数/偶数位置对元素进行分组,然后将每个组扩展为Tuple. 与ZipBrokenGlass 建议的方法相比,这种方法的好处在于它只枚举原始 enumerable 一次

然而,乍一看人们很难理解,所以我要么用另一种方式(即不使用 linq),要么在使用它的地方旁边记录它的意图。