Ajuda com List

Como eu faço para agrupar um list.
Eu preciso contar quantos registros tem iguais.

Por exemplo eu tenho um list contendo

1, Bruno
2, João
3, Maria
1, Bruno

Eu vou ter

1 Registro contendo 2, João
1 Registro contendo 3, Maria
2 Registros contendo 1, Bruno

Qual é o melhor jeito de fazer isso?

Estou precisando de uma luz

[]'s

Acho que nesse caso, vc poderia criar um método utilitário pra fazer o trabalho pra vc onde vc verificaria a quantidade um determinado item:

public static int qtd(List l, Object i){ int ret = 0; for(Object o : l){ if(o.equals(i)){ ++ret; } } return ret; }

Não encontrei algo pronto, mas acho que esse método ai em cima quebra bem o galho.

[]'s

Use um map, de String para Integer. E faça a contagem.

[code]Map<String, Integer> contagem = new TreeMap<String, Integer>();

for (String nome : listaDeNomes) {
if (!map.containsKey(nome)) {
map.put(nome, 1);
} else {
map.put(nome, map.get(nome)+1);
}
}

for (Map.Entry<String, Integer> entry : contagem.entrySet()) {
System.out.println("Nome: " + entry.getKey() + " Cont: " + entry.getValue());
}[/code]

Estava relendo aqui…

Para contar todos os itens da lista, seu método tem a pífia performance de O(N²). Isso quer dizer, que para testar 10 elementos, vc fará nada menos do que 100 comparações.

Para 100 elementos, já serão 10.000 comparações. E para 1000 elementos, serão 1000.000 de comparações.

Péssimo mesmo. Quando possível, tente fugir de for dentro de for.

 for (Map.Entry&lt;String, Integer&gt; entry : contagem) {  
     System.out.println("Nome: " + entry.getKey() + "  Cont: " + entry.getValue());  
 }  

Este for não está funcionando está dando erro no contagem
Can only iterate over an array on an instance of iterable

Preciso muito disso

Claro, estava errado mesmo:

for (Map.Entry&lt;String, Integer&gt; entry : contagem.entrySet()) {     
    System.out.println("Nome: " + entry.getKey() + "  Cont: " + entry.getValue());     
}    

Mas aquela é só a parte que imprime o mapa resultante. O cálculo mesmo está antes do for.

Em vez de usar Map tente usar o List.

Só varrer um cara do tipo list.

Algo do tipo: Nomes.get(i). E dps eh vc e sua lógica!!

Estava relendo aqui…

Para contar todos os itens da lista, seu método tem a pífia performance de O(N²). Isso quer dizer, que para testar 10 elementos, vc fará nada menos do que 100 comparações.

Para 100 elementos, já serão 10.000 comparações. E para 1000 elementos, serão 1000.000 de comparações.

Péssimo mesmo. Quando possível, tente fugir de for dentro de for.[/quote]

Sim, como eu disse, era pra quebrar um galho, mas mesmo assim se o interesse for contar a quantidade de um determinado elemento convenhamos que é mais eficiente que o método q vc propôs não?

Ainda assim, vc precisa ver se realmente iria compensar a estrutura do map, pois dá uma olhada vc chama um containsKey em um if que internamente vai varrer o map procurando se existe algum objeto igual, e em segunda dá um put, mas caso já exista ainda faz um get e em seguinda um put…

Além disso seu código tambem tem um erro, pois vc declara o Map [color=blue]contagem[/color] e usa o [color=blue]map[/color].

Olha só o que o containsKey da TreeMap faz:

public boolean containsKey(Object key) { return getEntry(key) != null; }

final Entry<K,V> getEntry(Object key) { // Offload comparator-based version for sake of performance if (comparator != null) return getEntryUsingComparator(key); if (key == null) throw new NullPointerException(); Comparable<? super K> k = (Comparable<? super K>) key; Entry<K,V> p = root; while (p != null) { int cmp = k.compareTo(p.key); if (cmp < 0) p = p.left; else if (cmp > 0) p = p.right; else return p; } return null; }

Sim, eu sei. Você já tinha dito que era quebra-galho.
Mas agora, faça o que ele pediu, e teste segundo a observação que eu fiz: Totalize todos os elementos da lista.

O método que eu propus totaliza todos em uma única iteração. E já dá o resultado ordenado no final. Se não quiser ordenado, troque o TreeMap por um hashMap que tem um containsKey mais leve e trivial.

O código que eu coloquei era ilustrativo. Não abri meu eclipse para testa-lo, então deve conter erros sim. Mas ele consegue transmitir a idéia.

PS: Apesar do containsKey parecer extremamente complexo, o que ele faz é percorrer uma árvore, e decidir se um elemento já está no mapa, o que ele em 2 ou 3 testes. Muito menos que identificar isso num list. É rápido que o tempo dificilmente será um problema. E, como eu falei, sempre pode-se recorrer ao HashMap.

Ainda asim, você ainda pode poupar um pouco e usar através do get, assim:

[code]
Map<String, Integer> map = new TreeMap<String, Integer>();

for (String nome : listaDeNomes) {
Integer cont = map.get(nome);
map.put(nome, cont == null ? 1 : cont+1);
}

for (Map.Entry<String, Integer> entry : contagem.entrySet()) {
System.out.println("Nome: " + entry.getKey() + " Cont: " + entry.getValue());
}[/code]

E, como eu disse, só para totalizar a lista toda, como seria desejável numa função estatística, ou num total de relatório, ou em outras situações práticas, que seu método é extremamente ineficiente. Para totalizar um único elemento, ok, ele vai ter uma performance um pouco melhor, mas só com milhares de elementos para diferença ser perceptível.

O problema seria que, para totalizar a lista toda, seu método teria que ser chamado várias vezes: uma para cada nome dentro da lista. Se alguém achar uma solução tão fácil de implementar quanto e melhor que o map, sou todo ouvidos.

O que significa que o seu método fica ineficiente numa escala exponencial, quando usado para todos os nomes do list. Gosto de ressaltar situações assim, porque geralmente testamos com poucos elementos no desenvolvimento, e a surpresa virá só em bases de produção.

A solução com o map tem um acrescimo linear de tempo.

[quote=ViniGodoy]PS: Apesar do containsKey parecer extremamente complexo, o que ele faz é percorrer uma árvore, e decidir se um elemento já está no mapa, o que ele em 2 ou 3 testes. Muito menos que identificar isso num list. É rápido que o tempo dificilmente será um problema. E, como eu falei, sempre pode-se recorrer ao HashMap.

Ainda asim, você ainda pode poupar um pouco e usar através do get, assim:

[code]
Map<String, Integer> map = new TreeMap<String, Integer>();

for (String nome : listaDeNomes) {
Integer cont = map.get(nome);
map.put(nome, cont == null ? 1 : cont+1);
}

for (Map.Entry<String, Integer> entry : contagem.entrySet()) {
System.out.println("Nome: " + entry.getKey() + " Cont: " + entry.getValue());
}[/code]

E, como eu disse, só para totalizar a lista toda, como seria desejável numa função estatística, ou num total de relatório, ou em outras situações práticas, que seu método é extremamente ineficiente. Para totalizar um único elemento, ok, ele vai ter uma performance um pouco melhor, mas só com milhares de elementos para diferença ser perceptível.

O problema seria que, para totalizar a lista toda, seu método teria que ser chamado várias vezes: uma para cada nome dentro da lista. Se alguém achar uma solução tão fácil de implementar quanto e melhor que o map, sou todo ouvidos.

O que significa que o seu método fica ineficiente numa escala exponencial, quando usado para todos os nomes do list. Gosto de ressaltar situações assim, porque geralmente testamos com poucos elementos no desenvolvimento, e a surpresa virá só em bases de produção.

A solução com o map tem um acrescimo linear de tempo.[/quote]

Concordo plenamente!!!

Como que eu faço pra colocar o resultado do value em outro map?

O construtor do mapa faz cópia:

Map&lt;String, Integer&gt; outroMapa = new HashMap&lt;String, Integer&gt;(mapa);