Здравствуйте, SuhanovSergey, Вы писали:
SS>интервьювер: нужно написать Linq запрос, выбирающий самую длинную непрерывную последовательность
SS>кандидат: как-то так
SS>SS>var maxElt = SplitToEqualRanges(s).Aggregate((Tuple<object, int>)null, (max, i) => max == null || i.Item2 > max.Item2 ? i : max);
SS> static IEnumerable<Tuple<T, int>> SplitToEqualRanges<T>(IEnumerable<T> sequence)
SS>{
SS> T current = default(T);
SS> int currentLen = 0;
SS> foreach (var i in sequence)
SS> {
SS> if (currentLen == 0)
SS> {
SS> current = i;
SS> }
SS> else if (!current.Equals(i))
SS> {
SS> yield return new Tuple<T, int>(current, currentLen);
SS> current = i;
SS> currentLen = 0;
SS> }
SS> ++currentLen;
SS> }
SS> if (currentLen > 0)
SS> yield return new Tuple<T, int>(current, currentLen);
SS>}
SS>
SS>интервьювер: тут мало Linq-а и слишком императивно
SS>кандидат: зато
SS>- это понятнее, чем многоэтажный Linq
SS>- гарантированно потребляет минимум ресурсов (O(1) памяти и O(n) времени)
SS>- проходит по последовательно один раз, что позволяет передавать последовательности неизвестной заранее длины
SS>интервьювер: чтобы пройти наш тест ваше решение должно содержать как минимум 5 Linq вызовов
SS>кандидат: хорошо. Вот новое решение со всеми достоинствами предыдущего, и удовлетворяещее вашему требованию
SS>SS>var maxElt2 =
SS> s.Zip(Enumerable.Range(0, s.Length), (elt, i) => new { Elt = elt, Idx = i })
SS> .ZipWithPrev()
SS> .Where(i => i.Item1.Idx == 0 || !i.Item1.Elt.Equals(i.Item2.Elt))
SS> .Select(i => i.Item1)
SS> .Concat(Enumerable.Repeat(new { Elt = (object)null, Idx = s.Length }, 1))
SS> .ZipWithPrev()
SS> .Skip(1)
SS> .Select(i => new {Elt=i.Item2.Elt, Len = i.Item1.Idx - i.Item2.Idx})
SS> .Aggregate((max, i) => max == null || i.Len > max.Len ? i : max);
SS>static IEnumerable<Tuple<T, T>> ZipWithPrev<T>(this IEnumerable<T> s)
SS>{
SS> T prev = default(T);
SS> foreach (var i in s)
SS> {
SS> yield return new Tuple<T, T>(i, prev);
SS> prev = i;
SS> }
SS>}
SS>
SS>интервьювер: совсем другое дело! хоть сейчас в продакшен!
Хватило бы и обычного foldl:
Object[] s = { "w", "a", "a", "a", "b", "b", "b", "b", "f", "a", "w", "w", "a", "b" };
var foldResult = s.Aggregate(new Tuple<int,object,int,object> (0, null, 0, null), (acc, item) => {
if(acc.Item2 != item)
{
// Reset
acc = new Tuple<int, object, int, object>(1, item, acc.Item3, acc.Item4);
}
else
{
// Increase
acc = new Tuple<int, object, int, object>(acc.Item1+1,acc.Item2, acc.Item3, acc.Item4);
}
if(acc.Item3 < acc.Item1)
{
// Maximum
acc = new Tuple<int, object, int, object>(acc.Item1, acc.Item2, acc.Item1, acc.Item2);
}
return acc;
});
Console.WriteLine("(Item:Count) -> ({0}:{1})", foldResult.Item4, foldResult.Item3);