Re[2]: Самая длинная непрерывная последовательность
От: 1067  
Дата: 03.08.12 22:56
Оценка:
Здравствуйте, 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);
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.