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.