Возьмите каждый второй объект в списке - PullRequest
7 голосов
/ 25 августа 2010

У меня есть IEnumerable, и я хочу получить новый IEnumerable, содержащий каждый n-й элемент.

Можно ли это сделать в Linq?

Ответы [ 3 ]

23 голосов
/ 25 августа 2010

Просто сам разобрался ...

Метод IEnumerable<T>.Where() имеет перегрузку, которая принимает индекс текущего элемента - именно то, что доктор прописал.

(new []{1,2,3,4,5}).Where((elem, idx) => idx % 2 == 0);

Этовернул бы

{1, 3, 5}

Обновление: чтобы охватить как мой вариант использования, так и предложение Дэна Тао, давайте также уточним, каким должен быть первый возвращаемый элемент:

var firstIdx = 1;
var takeEvery = 2;
var list =  new []{1,2,3,4,5};

var newList = list
    .Skip(firstIdx)
    .Where((elem, idx) => idx % takeEvery == 0);

... будетвозврат

{2, 4}
8 голосов
/ 25 августа 2010

Для реализации предложение Кристи :

public static IEnumerable<T> Sample<T>(this IEnumerable<T> source, int interval)
{
    // null check, out of range check go here

    return source.Where((value, index) => (index + 1) % interval == 0);
}

Использование:

var upToTen = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

var evens = upToTen.Sample(2);
var multiplesOfThree = upToTen.Sample(3);
0 голосов
/ 25 августа 2010

Пока не LINQ, вы также можете создать метод расширения с помощью yield.

public static IEnumerable<T> EverySecondObject<T>(this IEnumerable<T> list)
{
    using (var enumerator = list.GetEnumerator())
    {
        while (true)
        {
            if (!enumerator.MoveNext())
                yield break;
            if (enumerator.MoveNext())
                yield return enumerator.Current;
            else
                yield break;
        }
    }
}
...