Como obter os primeiros N elementos de uma lista em C #?


384

Gostaria de usar o Linq para consultar uma programação de ônibus em meu projeto, para que a qualquer momento possa obter os próximos 5 horários de chegada de ônibus. Como posso limitar minha consulta aos 5 primeiros resultados?

De maneira mais geral, como posso obter uma fatia de uma lista em C #? (Em Python, eu usaria mylist[:5]para obter os 5 primeiros elementos.)

Respostas:


709
var firstFiveItems = myList.Take(5);

Ou para cortar:

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

E, claro, muitas vezes é conveniente obter os cinco primeiros itens de acordo com algum tipo de ordem:

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

87
Ele lança exceção se houver apenas, por exemplo, 3 itens na lista? Ou serão necessários quantos forem até 5?
— 22412 bobek

87
@bobek: Não lança uma exceção. Ele simplesmente retorna o que possui se não houver elementos suficientes.
— 19372 Joshua Pech

11
exatamente, sem exceções jogado Skip e Take combinado resolveu o meu problema como eu queria tomar qualquer coleção genérica e processo de x itens por lote
— JohanLarsson

Note-se que .Take(n)retorna um TakeIterator; ele não retorna uma lista com nelementos (assumindo que muitos estão disponíveis). Use .ToArray()ou .ToList()no resultado de Takepara obter uma matriz ou lista concreta.
— Andrew Webb

69

Caso alguém esteja interessado (mesmo que a pergunta não solicite esta versão), o C # 2 seria: (Eu editei a resposta, seguindo algumas sugestões)

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

Talvez adicione um predicado anônimo também?
— AlexeyMK 26/11/08

2
Lista <T> .Sort retorna nulo; você precisaria classificar e usar GetRange separadamente. Você também pode usar um método anônimo Comparação <T> para remover a necessidade de CLASS_FOR_COMPARER.
— Marc Gravell

@AlexeyMK - você quer dizer uma comparação <T>, não um predicado (Predicate <T>) - um predicado é usado para filtrar dados
— Marc Gravell

Acredito que essa resposta seja útil agora, 10 anos e muitas versões de C # posteriormente. Para o caso específico em que você tem uma lista. Especialmente se você estiver pulando muitos itens. Por exemplo, você tem uma lista de um milhão de itens e deseja uma fatia de 5 deles, dentro da lista. O GetRange sabe exatamente onde ir para pegá-los. Não sei se o Skip+ Takeé tão inteligente ou se enumera sobre os itens ignorados. E eu não preciso saber - eu apenas uso GetRange (quando recebemos uma lista). Apenas certifique-se de perceber que o segundo parâmetro é count (em vez do último índice ).
— Home

O bom .Take(n)é que você não precisa se preocupar se houver menos de nelementos na sequência em que ele funciona. O problema List<T>.GetRange(0, count)é que você precisa se preocupar .... você receberá um ArgumentExceptionse não houver countitens.
— Andrew Webb

5

Como paginationvocê pode usar a fórmula abaixo para tomar slice of list or elements:

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

Exemplo 1: cinco primeiros itens

var pageNumber = 1;
var pageSize = 5;

Exemplo 2: segundo cinco itens

var pageNumber = 2;
var pageSize = 5;

Exemplo 3: terceiro cinco itens

var pageNumber = 3;
var pageSize = 5;

Se o aviso para formular parâmetros pageSize = 5e pageNumberestiver sendo alterado, se você desejar alterar o número de itens no fatiamento, será alterado pageSize.


1

Para pegar os 5 primeiros elementos, use melhor expressões como esta:

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

ou

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

Será mais rápido que a variante orderBy, porque o mecanismo LINQ não examinará toda a lista devido à execução atrasada e não classificará toda a matriz.

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
Só que agora você está solicitando apenas os 5 primeiros elementos depois de selecioná-los. Pode ser mais rápido, mas também possui semânticas diferentes, com menor probabilidade de ser o que as pessoas realmente desejam alcançar.
— Greg Beech
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.