Как я могу взять еще 1 предмет из TakeWhile Линка? - PullRequest
16 голосов
/ 11 февраля 2010

(последняя строка кода интереса, остальное только для полного представления)

Используя следующий код, я хотел принимать VOTERS до тех пор, пока я не превысит необходимое количество голосов, но он останавливается непосредственно перед достижением этого максимального числа голосов, поэтому у моего пула избирателей на 1 голос меньше, чем я хотел ,

Есть ли чистый способ в LINQ, где я мог бы заставить его принимать голоса, пока он не набрал максимальное количество голосов? Я знаю, что мог бы добавить еще одного избирателя или сделать это в цикле, но мне любопытно, если бы вместо этого был хороший способ сделать это с помощью LINQ.

var voters = new List<Person>
                             {
                                 new Person("Alice", Vote.Yes ),
                                 new Person("Bob", Vote.Yes),
                                 new Person("Catherine", Vote.No),
                                 new Person("Denzel", Vote.Yes),
                                 new Person("Einrich", Vote.Abstain),
                                 new Person("Frederica", Vote.Abstain),
                                 new Person("Goeffried", Vote.Abstain),
                             };
            voters.Single(c => c.Name == "Alice").Voices = 100;
            voters.Single(c => c.Name == "Bob").Voices = 150;
            voters.Single(c => c.Name == "Catherine").Voices = 99;
            voters.Single(c => c.Name == "Denzel").Voices = 24;
            voters.Single(c => c.Name == "Einrich").Voices = 52;
            voters.Single(c => c.Name == "Frederica").Voices = 39;
            voters.Single(c => c.Name == "Goeffried").Voices = 99;

// this takes voters until we are BEFORE reaching X voices...
int voicesSoFar = 0;
int voicesNeeded = 300;
var eligibleVoters = voters.TakeWhile((p => (voicesSoFar += p.Voices) < voicesNeeded ));

Ответы [ 5 ]

23 голосов
/ 25 июля 2011

В ситуации, когда я хотел выполнить функцию до тех пор, пока она не достигла конечного состояния, я сделал:

public static IEnumerable<T> TakeUntilIncluding<T>(this IEnumerable<T> list, Func<T, bool> predicate)
{
    foreach(T el in list)
    {
        yield return el;
        if (predicate(el))
            yield break;
    }
}

работал на меня! Я думаю, что это решение, не зависящее от реализации, как у Джейсона, но более простое.

17 голосов
/ 11 февраля 2010

Вы ищете

voters.TakeWhile(p => {
   bool exceeded = voicesSoFar > voicesNeeded ;
   voicesSoFar += p.Voices;
   return !exceeded;
});

Если вы настаиваете на однострочнике, это сработает, сравнив предыдущее значение:

voters.TakeWhile(p => (voicesSoFar += p.Voices) - p.Voices < voicesNeeded);
7 голосов
/ 11 февраля 2010

Просто напишите свой собственный метод расширения:

static class IEnumerableExtensions {
    public static IEnumerable<T> TakeUntil<T>(
        this IEnumerable<T> elements,
        Func<T, bool> predicate
    ) {
        return elements.Select((x, i) => new { Item = x, Index = i })
                       .TakeUntil((x, i) => predicate(x.Item))
                       .Select(x => x.Item);
    }

    public static IEnumerable<T> TakeUntil<T>(
        this IEnumerable<T> elements,
        Func<T, int, bool> predicate
    ) {
        int i = 0;
        foreach (T element in elements) {
            if (predicate(element, i)) {
                yield return element;
                yield break;
            }
            yield return element;
            i++;
        }
    }
}

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

var eligibleVoters = voters.TakeUntil(
                         p => (voicesSoFar += p.Voices) >= voicesNeeded
                     );

foreach(var voter in eligibleVoters) {
    Console.WriteLine(voter.Name);
}

Выход:

Alice
Bob
Catherine
0 голосов
/ 02 ноября 2017

Я столкнулся с той же проблемой. Я использовал методы Union и Skip, так что брал, пока не стало

   IEnumerable<Something> newSomethings  = somethings.TakeWhile(s => s != stop).Union(new List<Something>(){stop});  

и для пропуска до

   IEnumerable<Something> newSomethings  = somethings.SkipWhile(s => s != stop).Skip(1);  

Существует также метод Take, который принимает некоторые первые результаты.

0 голосов
/ 16 февраля 2017

Вариация ответа Коби, но демонстрирует использование (value, index). index полезен для решения подобных проблем, хотя и не для ОП.

voters.TakeWhile((value, index) => (voicesSoFar += value.Voices) - value.Voices < voicesNeeded);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...