Estou escrevendo um programa para definir uma sequência na qual vários objetos aparecerão no relatório. A sequência é a posição Y (célula) na planilha do Excel.
Uma parte de demonstração do código está abaixo. O que desejo realizar é ter uma coleção, o que me permitirá adicionar vários objetos e posso obter uma coleção ordenada com base na sequência
SortedList list = new SortedList();
Header h = new Header();
h.XPos = 1;
h.name = "Header_1";
list.Add(h.XPos, h);
h = new Header();
h.XPos = 1;
h.name = "Header_2";
list.Add(h.XPos, h);
Eu sei que a SortedList não permitirá isso e estou procurando uma alternativa. Não quero eliminar as duplicatas e já tentei List<KeyValuePair<int, object>>
.
Obrigado.
c#
.net
linq
collections
sortedlist
Mayur Kotlikar
fonte
fonte
List
?Respostas:
Use seu próprio IComparer!
Como já foi dito em algumas outras respostas, você deve usar sua própria classe de comparação. Para isso, uso uma classe IComparer genérica, que funciona com qualquer coisa que implemente IComparable:
Você o usará ao criar uma nova SortedList, SortedDictionary etc:
Aqui, int é a chave que pode ser duplicada.
fonte
SortedDictionary
. Ele também permite a remoção.Você pode usar List <> com segurança. The List tem um método Sort, uma sobrecarga que aceita IComparer. Você pode criar sua própria classe de classificação como. Aqui está um exemplo:
fonte
Eu uso o seguinte:
Meu caso de teste:
A saída:
fonte
O problema é que o design da estrutura de dados não atende aos requisitos: É necessário armazenar vários cabeçalhos para os mesmos XPos. Portanto,
SortedList<XPos, value>
não deve ter um valor deHeader
, mas um valor deList<Header>
. É uma mudança simples e pequena, mas que resolve todos os problemas e evita a criação de novos problemas como outras soluções sugeridas (ver explicação abaixo):Observe que adicionar uma chave "engraçada", como adicionar um número aleatório ou fingir que 2 XPos com o mesmo valor são diferentes, leva a muitos outros problemas. Por exemplo, torna-se difícil ou mesmo impossível remover um cabeçalho específico.
Observe também que o desempenho de classificação é muito melhor se apenas alguns
List<Header>
tiverem que ser classificados do que todosHeader
. Exemplo: se houver 100 XPos e cada um tiver 100 cabeçalhos, 10.000Header
precisam ser classificados em vez de 100List<Header>
.Obviamente, essa solução também tem uma desvantagem: se houver muitos XPos com apenas 1 cabeçalho, muitas Listas precisarão ser criadas, o que é uma sobrecarga.
fonte
Solução mais simples (em comparação com todas as anteriores): use
SortedSet<T>
, ele aceita umaIComparer<SortableKey>
classe e, em seguida, implemente o método Compare desta forma:fonte
Muito obrigado por sua ajuda. Enquanto procurava mais, encontrei esta solução. (Disponível em Stackoverflow.com em outra pergunta)
Primeiro, criei uma classe que encapsularia meus objetos para classes (cabeçalhos, rodapé etc)
Portanto, esta classe deve conter os objetos, e PosX de cada objeto vai como Int Position
O que eventualmente recebo é a lista classificada de "Sequência".
fonte
Você tentou
Lookup<TKey, TElement>
que permitirá chaves duplicadas http://msdn.microsoft.com/en-us/library/bb460184.aspxfonte
Lookup
I believe. Alguma boa maneira de contornar isso?ToLookup
em qualquerIEnumerable<T>
.Você pode usar SortedList, usar seu valor para TKey e int (contagem) para TValue.
Aqui está um exemplo: uma função que classifica as letras de uma palavra.
fonte
Esta classe de coleção irá manter duplicatas e inserir ordem de classificação para as duplicatas. O truque é marcar os itens com um valor exclusivo à medida que são inseridos para manter uma ordem de classificação estável. Em seguida, encerramos tudo em uma interface ICollection.
uma aula de teste
A estrutura de marcação
O ajudante comparador lambda
fonte
O problema é que você usa algo como chave que não é uma chave (porque isso ocorre várias vezes).
Portanto, se você tiver coordenadas reais, talvez deva considerar o
Point
como a chave para sua SortedList.Ou você cria um
List<List<Header>>
onde seu primeiro índice de lista define a posição x e o índice de lista interno a posição y (ou vice-versa, se preferir).fonte
A chave (trocadilho) para isso é criar uma
IComparable
classe baseada em-que mantém igualdade e hashing, mas nunca se compara a 0 se não for igual. Isso pode ser feito e pode ser criado com alguns bônus - classificação estável (ou seja, os valores adicionados à lista classificada primeiro manterão sua posição) eToString()
pode simplesmente retornar o valor da string de chave real.Aqui está uma chave de estrutura que deve fazer o truque:
fonte
Linq.Lookup é legal e tudo, mas se o seu objetivo é simplesmente fazer um loop sobre as "chaves" enquanto permite que sejam duplicadas, você pode usar esta estrutura:
Então você pode escrever:
HTH
fonte
O truque é aumentar seu objeto com uma chave exclusiva. Veja o seguinte teste que passa. Quero manter meus pontos classificados por seu valor X. Apenas usar um Point2D nu na minha função de comparação fará com que pontos com o mesmo valor X sejam eliminados. Portanto, envolvo o Point2D em uma classe de marcação chamada Indexada.
Os utilitários para fazer este trabalho são
Um comparador que leva um lambda
Uma estrutura de marcação
fonte
Foi assim que resolvi o problema. É feito para ser thread-safe, embora você possa simplesmente remover os
lock
s se não precisar disso. Observe também que arbitrárioInsert
em um índice não é suportado porque isso pode violar a condição de classificação.fonte
Crie uma classe e consulte a lista:
fonte
Aqui está minha opinião sobre isso. Esteja ciente, aqui podem ser dragões, C # ainda é bastante novo para mim.
Uso:
fonte
Queue
em BCL, que representa uma coleção de itens primeiro a entrar. A semântica de sua classe é diferente. Sua classe tem um começo (onde os itens são retirados da fila), mas não tem um fim (um item pode ser inserido em qualquer lugar). Portanto, oEnqueue
método em sua classe IMHO é sem sentido.PriorityQueue
seria o nome mais apropriado.-2 * 5 == +10
positivo ( ), então não é grande coisa. :-)