интервьювер: нужно написать Linq запрос, выбирающий самую длинную непрерывную последовательность
кандидат: как-то так
var maxElt = SplitToEqualRanges(s).Aggregate((Tuple<object, int>)null, (max, i) => max == null || i.Item2 > max.Item2 ? i : max);
static IEnumerable<Tuple<T, int>> SplitToEqualRanges<T>(IEnumerable<T> sequence)
{
T current = default(T);
int currentLen = 0;
foreach (var i in sequence)
{
if (currentLen == 0)
{
current = i;
}
else if (!current.Equals(i))
{
yield return new Tuple<T, int>(current, currentLen);
current = i;
currentLen = 0;
}
++currentLen;
}
if (currentLen > 0)
yield return new Tuple<T, int>(current, currentLen);
}
интервьювер: тут мало Linq-а и слишком императивно
кандидат: зато
— это понятнее, чем многоэтажный Linq
— гарантированно потребляет минимум ресурсов (O(1) памяти и O(n) времени)
— проходит по последовательно один раз, что позволяет передавать последовательности неизвестной заранее длины
интервьювер: чтобы пройти наш тест ваше решение должно содержать как минимум 5 Linq вызовов
кандидат: хорошо. Вот новое решение со всеми достоинствами предыдущего, и удовлетворяещее вашему требованию
var maxElt2 =
s.Zip(Enumerable.Range(0, s.Length), (elt, i) => new { Elt = elt, Idx = i })
.ZipWithPrev()
.Where(i => i.Item1.Idx == 0 || !i.Item1.Elt.Equals(i.Item2.Elt))
.Select(i => i.Item1)
.Concat(Enumerable.Repeat(new { Elt = (object)null, Idx = s.Length }, 1))
.ZipWithPrev()
.Skip(1)
.Select(i => new {Elt=i.Item2.Elt, Len = i.Item1.Idx - i.Item2.Idx})
.Aggregate((max, i) => max == null || i.Len > max.Len ? i : max);
static IEnumerable<Tuple<T, T>> ZipWithPrev<T>(this IEnumerable<T> s)
{
T prev = default(T);
foreach (var i in s)
{
yield return new Tuple<T, T>(i, prev);
prev = i;
}
}
интервьювер: совсем другое дело! хоть сейчас в продакшен!