Как получить элементы из списка?

192
03 марта 2019, 23:30

Есть метод переопределения, который вытаскивает последние n-элементов списка. Допустим списке у меня 10 элементов, а хочу я получить 100 элементов. Как заполнить эти 90 элементов нулями?

public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> source, int takeCount)
{
    if (source == null) { throw new ArgumentNullException("source"); }
    if (takeCount < 0) { throw new ArgumentOutOfRangeException("takeCount", "must not be negative"); }
    if (takeCount == 0) { yield break; }
    T[] result = new T[takeCount];
    int i = 0;
    int sourceCount = 0;
    foreach (T element in source)
    {
        result[i] = element;
        i = (i + 1) % takeCount;
        sourceCount++;
    }
    if (sourceCount < takeCount)
    {
        takeCount = sourceCount;
        i = 0;
    }
    for (int j = 0; j < takeCount; ++j)
    {
        yield return result[(i + j) % takeCount];
    }
}
Answer 1

Для того, чтобы вернуть некоторое количество элементов с конца последовательности, нам нужно перебрать все ее элементы, поэтому считаю приемлемым переписать ваш метод таким образом:

public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> source, int takeCount)
{
    if (source == null) throw new ArgumentNullException(nameof(source));
    if (takeCount < 0) throw new ArgumentOutOfRangeException(nameof(takeCount), "must not be negative");
    if (takeCount == 0) return Enumerable.Empty<T>();
    return source.Reverse().Take(takeCount).Reverse();
}

Ну и, т. к. заведомо count + takeCount >= takeCount, можно дополнить исходную последовательность значениями def в количестве takeCount шт.:

public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> source, int takeCount, T def = default)
{
    ...
    return source.Reverse().Take(takeCount).Reverse()
        .Concat(Enumerable.Repeat(def, takeCount)).Take(takeCount);
}

Еще один вариант, который не будет хранить абсолютно все элементы входной последовательности без необходимости:

public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> source, int takeCount, T def = default)
{
    ...
    var queue = new Queue<T>(takeCount);
    foreach (var item in source)
    {
        if (queue.Count == takeCount) queue.Dequeue();
        queue.Enqueue(item);
    }
    return queue.Concat(Enumerable.Repeat(def, Math.Max(0, takeCount - queue.Count)));
}

Очередь (System.Collections.Generic.Queue<T>) использует внутри такой же подход с "циклическим массивом", что и у вас.

READ ALSO
Подскажите разницу между классами Monitor и Mutex

Подскажите разницу между классами Monitor и Mutex

Теоретический вопросЕсли нам нужно синхронизировать потоки, то в большинстве случаев наверное достаточно lock, это почти то же самое, что...

212
Многомерный массив c#

Многомерный массив c#

Есть 2 строки в файле вида

239
wpf привязка (обновление данных)

wpf привязка (обновление данных)

есть класс Project (модель) с некиеми методами:

186
Как достать список из таблицы БД?

Как достать список из таблицы БД?

Я получил список категорий из БДДалее мне нужно получить из соседней таблицы все топики, которые относятся к данной категории

244