Ordenar Map

Senhores eu tenho esse trecho de código que faz o seguinte:
1 - verifica se já existe no map a chave “MES/ANO”
2 - coloca o registro no seu respectivo mes ano

if (!map.containsKey(data.getMes() + "/" + data.getAno()))
    map.put(data.getMes() + "/" + data.getAno(),new ArrayList());

((ArrayList) map.get(data.getMes() + "/" + data.getAno())).add(registro);

No final eu terei o seguinte map

01/2007 - registros
05/2007 - registros
02/2007 - registros

então eis a questão:
Como ordernar este MAP por “mes ano” ???

Obrigado turma.

  1. Escreva um Comparator para a sua chave (se ela já não for Comparable);
  2. Copie os dados do seu map para um TreeMap.

O TreeMap já é ordenado.

Você pode esclarecer um pouco mais?

minha chave é uma string.
com isso tenho até um problema ao ordenar uma string o 10 vem antes do 1.

Leia o seguinte tutorial:
http://java.sun.com/docs/books/tutorial/collections/interfaces/order.html

Aqui explica ordenação de listas e o comparator.

O TreeMap é uma lista que sempre se mantém ordenada, desde q vc forneça um comparator para a chave.

olha aqui como fica…
a ordenação entende o 10/2007 menor que 2/2007


Por isso eu disse que você teria que implementar o seu próprio Comparator.
Se você depender unicamente do comparador de Strings, não dá certo mesmo.

Um comparator mais correto seria:

[code]
class DataComparator implements Comparator
{
public int compare(String o1, String o2) {
String[] diaEMes1 = o1.split("/");
String[] diaEMes2 = o2.split("/");

     int mes1 = Integer.parseInt(diaEMes1[0]);
     int ano1 = Integer.parseInt(diaEMes1[1]);
     
     int mes2 = Integer.parseInt(diaEMes2[0]);         
     int ano2 = Integer.parseInt(diaEMes2[1]);
     

     int compare = ano1 - ano2; //Começamos pelo ano
     
     if (compare != 0) 
         return compare;
     
     return mes1 - mes2; //E se o ano for igual, comparamos o mês

}
}[/code]

Daí vc cria o seu TreeMap usando esse comparator.

Map<String, List> map = new TreeMap<String, List>(new DateStringComparator());

Outra alternativa criar uma classe, comparable, que represente o mês e o dia. E então usar ela de chave no seu mapa.

PS: Acho a outra alternativa muito mais elegante.

Crie uma classe:

[code]public MesAno implements Comparable {
private int mes;
private int ano;
public MesAno(Data data) {
this.mes = mes;
this.ano = ano;
}

public int getMes() { return mes; }
public int getAno() { return ano; }

public int compareTo(MesAno other) {
int compare = ano - other.ano;
if (compare != 0) return compare;
return mes - other.mes;
}

public String toString() {
return mes “/” + ano;
}
}[/code]

Depois, passe a usar objetos dessa classe no seu mapa:

[code]MesAno mesEAno = new MesAno(data);
if (!map.containsKey(mesEAno)
map.put(mesEAno, new ArrayList());

(ArrayList) map.get(mesEAno).add(registro);[/code]

A vantagem é que, se você precisar mudar o formato da data, a ordem dos registros, ou mesmo incluir informação adicional na chave, pode fazer apenas mudando a classe MesAno. Isso também evita os parseInts e um comparator muito complexo.

Conforme sugere o Joshua Bloch no livro Effective Java, a classe String só deve ser usada para valores que representam texto. No caso, a sua chave é um valor que presenta uma data no formato MesEAno. Por isso, é melhor criar uma classe separada. Ela pode provar ser muito mais útil com o passar do tempo.

amigo… essa da classe mes ano é bem legal…
desculpe-me pelo desconhecimento e me diga: preciso fazer algo mais do que implementar a classe e popular o map. porque continua botando o 10 na frente do 1 o resto está ordenando corretamento ex. 02/2007 - 03/2007 …

Se o seu mês for uma string, tem que converter para int.

Se já for int, não precisaria fazer nada…

Ah, seria bom implementar o equals e o hashCode da classe MesAno também.

[code]public boolean equals(Object o) {
if (o.getClass() != getClass())
return false;
return compareTo((MesAno)o) == 0;
}

//Um hash simples.
//Mas deve ser suficiente para esse caso.
public int hashCode() {
return ano * 100 + mes;
}
[/code]

exatamente!

na classe MesAno o meu construtor recebe a data que contém tanto o ano como o mes em int.
porém, continua colocando o 10/2007 na frente do 2/2007.

public MesAno(Data data) {
this.mes = data.getMes();
this.ano = data.getAno();
}

Estranho, será que o seu componente que está gerando o gráfico não está fazendo caquinha?
Teste se seu mapa está ordenado fazendo um println nas chaves.

Se o mapa estiver errado, então deve ser um problema com o Comparator.

Se estiver certo é o componente do relatório que tá fazendo caca…

é amigo… eu já tinha testado o mapa antes de apresentar no jsp e ele já tras a caca consigo.

Você está usando um TreeMap?

Deu certo… eu estava refazendo o map aí ele deserdenava…
muito o brigado pela atenção.

olá,
tenho um HashMap<Character, Integer>
queria uma maneira de saber qual chave tem o menor valor, para depois excluí-la,
usei o TreeMap, mas ele ordena tudo doido.
tem como ele ordenar pelos valores? ou tenho de implementar esse Coparator?

outra dúvida, achei uma classe PriorityQueue, que é uma fila que ordena pelo menor. consegui usá-la com array, mas não consegui com o meu HashMap, não teria como eu usar o hashMap nessa classe?

obrigado!

Rapaz… uma dica. Abra seu próprio tópico, não pegue carona no dos outros.

O TreeMap vai ordenar pela chave, não pelos valores.

Se você precisa ordenar os valores, copie-os para uma set ordenado:

SortedSet valoresOrdenados = new TreeSet(map.values());

Agora, você quer excluir por um valor ou por uma chave?

Não sua segunda pergunta. Na verdade entendi o que você quer fazer. Pode abrir um novo tópico com a dúvida?