Як отримати перші N елементів списку в C #?


384

Я хотів би використати Linq для запиту розкладу автобусів у своєму проекті, щоб у будь-який час я міг отримати наступні 5 разів прибуття автобуса. Як я можу обмежити свій запит першими 5 результатами?

Більш загально, як я можу взяти фрагмент списку в C #? (У Python я б використав, mylist[:5]щоб отримати перші 5 елементів.)

Відповіді:


706
var firstFiveItems = myList.Take(5);

Або нарізати:

var secondFiveItems = myList.Skip(5).Take(5);

І звичайно, часто зручно отримувати перші п’ять предметів за якимсь замовленням:

var firstFiveArrivals = myList.OrderBy(i => i.ArrivalTime).Take(5);

87
Чи кидає виняток, якщо у списку є лише, наприклад, 3 пункти? Або знадобиться стільки, скільки їх до 5?
bobek

87
@bobek: Це не кидає винятку. Він просто повертає те, що є, якщо не вистачає елементів.
Джошуа Печ

1
точно, жодних винятків, кинутих Пропустити та взяти разом, вирішив мою проблему, оскільки я хотів взяти будь-яку загальну колекцію та обробляти х предметів за партію
JohanLarsson

Слід зазначити, що .Take(n)повертає TakeIterator; він не повертає список з nелементами в ньому (якщо припустити, що їх багато). Для отримання конкретного масиву чи списку скористайтесь .ToArray()або .ToList()за результатами Take.
Ендрю Вебб

69

Якщо хтось зацікавлений (навіть якщо питання не задає цю версію), у C # 2 буде: (я відредагував відповідь, дотримуючись деяких пропозицій)

myList.Sort(CLASS_FOR_COMPARER);
List<string> fiveElements = myList.GetRange(0, 5);

Може також додати анонімний присудок?
AlexeyMK

2
Список <T> .Sort повертає недійсність; вам потрібно буде сортувати, а потім використовувати GetRange окремо. Ви також можете використовувати анонімний метод Порівняння <T>, щоб усунути потребу в CLASS_FOR_COMPARER.
Марк Гравелл

@AlexeyMK - ти маєш на увазі Порівняння <T>, а не присудок (предикат <T>) - присудок використовується для фільтрації даних
Марк Гравелл

Я вважаю, що ця відповідь корисна навіть зараз, через 10 років та багато версій C # пізніше. Для конкретного випадку, коли у вас є список. Особливо, якщо ви пропускаєте багато предметів. Наприклад, у вас є список з мільйона предметів, і ви хочете, щоб фрагмент з них був 5, далеко в списку. GetRange точно знає, куди піти, щоб схопити їх. Я не знаю, чи Skip+ Takeнастільки розумний, чи він перераховується за пропущеними елементами. І мені не потрібно знати - я просто використовую GetRange (коли мені надають список). Просто переконайтеся, що ви усвідомлюєте, що другий параметр є підрахунком (а не останнім індексом )
ToolmakerSteve

Приємно в тому .Take(n), що вам не потрібно хвилюватися, якщо nв послідовності, в якій вона працює, є менше елементів. Проблема List<T>.GetRange(0, count)полягає в тому, що вам доведеться хвилюватися .... ви отримаєте, ArgumentExceptionякщо немає countпредметів.
Ендрю Вебб

5

Як paginationви можете використовувати нижче формулу для прийому slice of list or elements:

var slice = myList.Skip((pageNumber - 1) * pageSize)
                  .Take(pageSize);

Приклад 1: перші п’ять пунктів

var pageNumber = 1;
var pageSize = 5;

Приклад 2: друге п’ять пунктів

var pageNumber = 2;
var pageSize = 5;

Приклад 3: треті п’ять предметів

var pageNumber = 3;
var pageSize = 5;

Якщо повідомлення formulė параметри pageSize = 5і pageNumberзмінюється, якщо ви хочете , щоб номер зміни елементів в нарізці зміни pageSize.


1

Щоб взяти перші 5 елементів, краще використовуйте вираз, як цей:

var firstFiveArrivals = myList.Where([EXPRESSION]).Take(5);

або

var firstFiveArrivals = myList.Where([EXPRESSION]).Take(5).OrderBy([ORDER EXPR]);

Це буде швидше, ніж варіант orderBy, тому що двигун LINQ не просканує через весь список через затримку виконання та не сортуватиме весь масив.

class MyList : IEnumerable<int>
{

    int maxCount = 0;

    public int RequestCount
    {
        get;
        private set;
    }
    public MyList(int maxCount)
    {
        this.maxCount = maxCount;
    }
    public void Reset()
    {
        RequestCount = 0;
    }
    #region IEnumerable<int> Members

    public IEnumerator<int> GetEnumerator()
    {
        int i = 0;
        while (i < maxCount)
        {
            RequestCount++;
            yield return i++;
        }
    }

    #endregion

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }

    #endregion
}
class Program
{
    static void Main(string[] args)
    {
        var list = new MyList(15);
        list.Take(5).ToArray();
        Console.WriteLine(list.RequestCount); // 5;

        list.Reset();
        list.OrderBy(q => q).Take(5).ToArray();
        Console.WriteLine(list.RequestCount); // 15;

        list.Reset();
        list.Where(q => (q & 1) == 0).Take(5).ToArray();
        Console.WriteLine(list.RequestCount); // 9; (first 5 odd)

        list.Reset();
        list.Where(q => (q & 1) == 0).Take(5).OrderBy(q => q).ToArray();
        Console.WriteLine(list.RequestCount); // 9; (first 5 odd)
    }
}

25
За винятком того, що ви замовляєте лише перші 5 елементів після того, як ви їх вибрали. Це може бути швидше, але воно також має різну семантику, що рідше є тим, чого люди насправді хочуть досягти.
Грег Бук
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.