Existe uma boa maneira de dividir uma coleção em n
partes com o LINQ? Não necessariamente igualmente, é claro.
Ou seja, quero dividir a coleção em sub-coleções, cada uma contendo um subconjunto dos elementos, onde a última coleção pode ser irregular.
c#
.net
linq
data-structures
Simon_Weaver
fonte
fonte
Respostas:
Um linq puro e a solução mais simples são mostrados abaixo.
fonte
.AsEnumerable()
não é necessário, IGrouping <T> já é um IEnumerable <T>.EDIT: Ok, parece que eu interpretei errado a pergunta. Eu li como "pedaços de comprimento n" em vez de "n pedaços". Doh! Considerando a exclusão da resposta ...
(Resposta original)
Não acredito que exista uma maneira interna de particionar, embora pretenda escrever uma no meu conjunto de adições ao LINQ to Objects. Marc Gravell tem uma implementação aqui, embora eu provavelmente a modifique para retornar uma exibição somente leitura:
fonte
yield return
. Requer que um lote esteja na memória de cada vez, mas é tudo.fonte
var dept = {1,2,3,4,5}
. Depois de dividir o resultado é comodept1 = {1,3,5}
edept2 = { 2,4 }
ondeparts = 2
. Mas o resultado que eu preciso édept1 = {1,2,3}
edept2 = {4,5}
int columnLength = (int)Math.Ceiling((decimal)(list.Count()) / parts);
e fiz a divisão com.GroupBy(x => x.index / columnLength)
. Uma desvantagem é Count () enumera a lista.Ok, eu vou jogar meu chapéu no ringue. As vantagens do meu algoritmo:
O código:
Conforme apontado nos comentários abaixo, essa abordagem não aborda a questão original, que solicitou um número fixo de seções de comprimento aproximadamente igual. Dito isso, você ainda pode usar minha abordagem para resolver a questão original chamando-a desta maneira:
Quando usada dessa maneira, a abordagem não é mais O (1), pois a operação Count () é O (N).
fonte
É o mesmo que a resposta aceita, mas uma representação muito mais simples:
O método acima divide um
IEnumerable<T>
em N número de pedaços de tamanhos iguais ou quase iguais.O método acima divide um
IEnumerable<T>
em pedaços do tamanho fixo desejado com o número total de pedaços sem importância - e não é disso que se trata.O problema com o
Split
método, além de ser mais lento, é que ele embaralha a saída no sentido de que o agrupamento será feito com base no i-ésimo múltiplo de N para cada posição ou, em outras palavras, você não recebe os pedaços na ordem original.Quase todas as respostas aqui não preservam a ordem, ou são sobre particionamento e não são divididas, ou estão claramente erradas. Tente isso mais rápido, preserva a ordem, mas um pouco mais detalhado:
O método equivalente para uma
Partition
operação aquifonte
Eu tenho usado a função Partition que publiquei anteriormente com bastante frequência. A única coisa ruim foi que não estava sendo transmitido completamente. Isso não é um problema se você trabalhar com poucos elementos em sua sequência. Eu precisava de uma nova solução quando comecei a trabalhar com mais de 100.000 elementos na minha sequência.
A solução a seguir é muito mais complexa (e mais código!), Mas é muito eficiente.
Aproveitar!
fonte
Tópico interessante. Para obter uma versão de streaming do Split / Partition, é possível usar enumeradores e gerar sequências do enumerador usando métodos de extensão. Converter código imperativo em código funcional usando yield é uma técnica muito poderosa.
Primeiro, uma extensão de enumerador que transforma uma contagem de elementos em uma sequência lenta:
E então uma extensão enumerável que particiona uma sequência:
O resultado final é uma implementação altamente eficiente, de streaming e lenta, que depende de um código muito simples.
Aproveitar!
fonte
Eu uso isso:
fonte
Isso é eficiente em memória e adia a execução o máximo possível (por lote) e opera em tempo linear O (n)
fonte
Há muitas ótimas respostas para essa pergunta (e seus primos). Eu mesmo precisava disso e havia criado uma solução projetada para ser eficiente e tolerante a erros em um cenário em que a coleção de fontes pode ser tratada como uma lista. Ele não usa nenhuma iteração lenta, por isso pode não ser adequado para coleções de tamanho desconhecido que possam aplicar pressão de memória.
Vi algumas respostas em toda essa família de perguntas que usam GetRange e Math.Min. Mas acredito que, no geral, essa é uma solução mais completa em termos de verificação de erros e eficiência.
fonte
fonte
Ótimas respostas, para o meu cenário, testei a resposta aceita e parece que ela não mantém a ordem. também há uma ótima resposta de Nawfal que mantém a ordem. Mas, no meu cenário, eu queria dividir o restante de uma maneira normalizada, todas as respostas que vi espalharam o restante ou no início ou no final.
Minha resposta também leva o restante a se espalhar de maneira mais normalizada.
fonte
Se a ordem nessas partes não for muito importante, você pode tentar o seguinte:
No entanto, estes não podem ser convertidos em IEnumerable <IEnumerable <int>> por algum motivo ...
fonte
Este é o meu código, agradável e curto.
fonte
Este é o meu caminho, listando itens e quebrando linhas por colunas
fonte
Eu estava procurando por uma divisão como a de string, então a lista inteira é dividida de acordo com alguma regra, não apenas a primeira parte, esta é a minha solução
fonte
Aqui está um pequeno ajuste para o número de itens em vez do número de peças:
fonte
fonte
Acabei de encontrar esse segmento, e a maioria das soluções aqui envolve adicionar itens às coleções, materializando efetivamente cada página antes de devolvê-la. Isso é ruim por dois motivos: primeiro, se suas páginas são grandes, há uma sobrecarga de memória para preencher a página; em segundo lugar, existem iteradores que invalidam os registros anteriores quando você avança para o próximo (por exemplo, se você agrupar um DataReader em um método de enumerador) .
Esta solução usa dois métodos de enumerador aninhado para evitar a necessidade de armazenar itens em cache em coleções temporárias. Como os iteradores externos e internos estão percorrendo o mesmo enumerável, eles necessariamente compartilham o mesmo enumerador, portanto, é importante não avançar o externo até que você termine o processamento da página atual. Dito isto, se você decidir não percorrer toda a página atual, quando você passar para a próxima página, esta solução irá percorrer o limite da página automaticamente.
fonte