Cómo contar el número de apariciones de un elemento en una lista

Tengo una ArrayList , una clase de colección de Java, de la siguiente manera:

 ArrayList animals = new ArrayList(); animals.add("bat"); animals.add("owl"); animals.add("bat"); animals.add("bat"); 

Como puede ver, los animals ArrayList consta de 3 elementos bat y un elemento owl . Me preguntaba si hay alguna API en el marco de recostackción que devuelva el número de ocurrencias de bat o si hay otra forma de determinar el número de apariciones.

Descubrí que Google Collection Multiset tiene una API que devuelve el número total de apariciones de un elemento. Pero eso solo es compatible con JDK 1.5. Nuestro producto se encuentra actualmente en JDK 1.6, por lo que no puedo usarlo.

Estoy bastante seguro de que el método de frecuencia estática en Colecciones sería útil aquí:

 int occurrences = Collections.frequency(animals, "bat"); 

Así es como lo haría de todos modos. Estoy bastante seguro de que esto es jdk 1.6 en línea recta.

En Java 8:

 Map counts = list.stream().collect(Collectors.groupingBy(e -> e, Collectors.counting())); 

Esto muestra por qué es importante ” Referir a objetos por sus interfaces ” como se describe en el libro Efectivo de Java .

Si codifica la implementación y usa ArrayList en, digamos, 50 lugares en su código, cuando encuentre una buena implementación de “Lista” que cuente los elementos, tendrá que cambiar esos 50 lugares, y probablemente tendrá que rompa su código (si solo lo usa, no es un gran problema, pero si lo usa alguien más, también romperá su código)

Al progtwigr en la interfaz, puede dejar esos 50 lugares sin cambios y reemplazar la implementación de ArrayList a “CountItemsList” (por ejemplo) o alguna otra clase.

A continuación hay una muestra muy básica sobre cómo se podría escribir esto. Esto es solo una muestra, una Lista de producción lista sería mucho más complicada.

 import java.util.*; public class CountItemsList extends ArrayList { // This is private. It is not visible from outside. private Map count = new HashMap(); // There are several entry points to this class // this is just to show one of them. public boolean add( E element ) { if( !count.containsKey( element ) ){ count.put( element, 1 ); } else { count.put( element, count.get( element ) + 1 ); } return super.add( element ); } // This method belongs to CountItemList interface ( or class ) // to used you have to cast. public int getCount( E element ) { if( ! count.containsKey( element ) ) { return 0; } return count.get( element ); } public static void main( String [] args ) { List animals = new CountItemsList(); animals.add("bat"); animals.add("owl"); animals.add("bat"); animals.add("bat"); System.out.println( (( CountItemsList )animals).getCount( "bat" )); } } 

Principios OO aplicados aquí: herencia, polymorphism, abstracción, encapsulación.

En realidad, la clase Colecciones tiene un método estático llamado: frecuencia (Colección c, Objeto o) que devuelve el número de apariciones del elemento que está buscando, dicho sea de paso, esto funcionará perfectamente para usted:

 ArrayList animals = new ArrayList(); animals.add("bat"); animals.add("owl"); animals.add("bat"); animals.add("bat"); System.out.println("Freq of bat: "+Collections.frequency(animals, "bat")); 

Lo sentimos, no hay una llamada de método simple que pueda hacerlo. Todo lo que necesitas hacer es crear un mapa y contar la frecuencia con él.

 HashMap frequencymap = new HashMap(); foreach(String a in animals) { if(frequencymap.containsKey(a)) { frequencymap.put(a, frequencymap.get(a)+1); } else{ frequencymap.put(a, 1); } } 

Me pregunto por qué no puedes usar la API de recostackción de Google con JDK 1.6. ¿Eso dice? Creo que puede, no debería haber problemas de compatibilidad, ya que está diseñado para una versión más baja. El caso habría sido diferente si eso fue construido para 1.6 y está ejecutando 1.5.

¿Me equivoco en algún lado?

No hay un método nativo en Java para hacer eso por usted. Sin embargo, puede usar IterableUtils # countMatches () de Apache Commons-Collections para hacerlo por usted.

Un enfoque un poco más eficiente podría ser

 Map instances = new HashMap(); void add(String name) { AtomicInteger value = instances.get(name); if (value == null) instances.put(name, new AtomicInteger(1)); else value.incrementAndGet(); } 

Solución alternativa de Java 8 utilizando Streams :

 long count = animals.stream().filter(animal -> "bat".equals(animal)).count(); 

Lo que quiere es una bolsa, que es como un conjunto pero también cuenta el número de ocurrencias. Desafortunadamente, el marco de colecciones de Java es genial, ya que no tienen una impl. Para eso uno debe usar el texto del enlace de la colección común de Apache

Para obtener las ocurrencias del objeto de la lista directamente:

 int noOfOccurs = Collections.frequency(animals, "bat"); 

Para obtener la aparición de la lista dentro de la colección de objetos, anule el método equals en la clase Object como:

 @Override public boolean equals(Object o){ Animals e; if(!(o instanceof Animals)){ return false; }else{ e=(Animals)o; if(this.type==e.type()){ return true; } } return false; } Animals(int type){ this.type = type; } 

Llame a Collections.frequency como:

 int noOfOccurs = Collections.frequency(animals, new Animals(1)); 

Manera simple de encontrar la ocurrencia del valor de cadena en una matriz usando las características de Java 8.

 public void checkDuplicateOccurance() { List duplicateList = new ArrayList(); duplicateList.add("Cat"); duplicateList.add("Dog"); duplicateList.add("Cat"); duplicateList.add("cow"); duplicateList.add("Cow"); duplicateList.add("Goat"); Map couterMap = duplicateList.stream().collect(Collectors.groupingBy(e -> e.toString(),Collectors.counting())); System.out.println(couterMap); } 

Salida: {Cat = 2, Cabra = 1, Vaca = 1, vaca = 1, Perro = 1}

Puedes notar que “vaca” y “vaca” no se consideran como la misma cadena, en caso de que lo requieras bajo el mismo conteo, usa .toLowerCase (). Encuentre el fragmento a continuación para el mismo.

 Map couterMap = duplicateList.stream().collect(Collectors.groupingBy(e -> e.toString().toLowerCase(),Collectors.counting())); 

Salida: {cat = 2, cow = 2, goat = 1, dog = 1}

Java 8 – otro método

 String searched = "bat"; long n = IntStream.range(0, animals.size()) .filter(i -> searched.equals(animals.get(i))) .count(); 

Si usa colecciones de Eclipse , puede usar una Bag . Se puede MutableBag un MutableBag desde cualquier implementación de RichIterable llamando a toBag() .

 MutableList animals = Lists.mutable.with("bat", "owl", "bat", "bat"); MutableBag bag = animals.toBag(); Assert.assertEquals(3, bag.occurrencesOf("bat")); Assert.assertEquals(1, bag.occurrencesOf("owl")); 

La implementación de HashBag en EC está respaldada por MutableObjectIntMap .

Nota: soy un committer para las colecciones de Eclipse.

Coloque los elementos del arraylist en el hashMap para contar la frecuencia.

 List list = Arrays.asList("as", "asda", "asd", "urff", "dfkjds", "hfad", "asd", "qadasd", "as", "asda", "asd", "urff", "dfkjds", "hfad", "asd", "qadasd" + "as", "asda", "asd", "urff", "dfkjds", "hfad", "asd", "qadasd", "as", "asda", "asd", "urff", "dfkjds", "hfad", "asd", "qadasd"); 

Método 1:

 Set set = new LinkedHashSet<>(); set.addAll(list); for (String s : set) { System.out.println(s + " : " + Collections.frequency(list, s)); } 

Método 2:

 int count = 1; Map map = new HashMap<>(); Set set1 = new LinkedHashSet<>(); for (String s : list) { if (!set1.add(s)) { count = map.get(s) + 1; } map.put(s, count); count = 1; } System.out.println(map); 

Así que hágalo a la vieja usanza y haga su propia versión:

 Map instances = new HashMap(); void add(String name) { Integer value = instances.get(name); if (value == null) { value = new Integer(0); instances.put(name, value); } instances.put(name, value++); } 

Si usted es un usuario de mi ForEach DSL , puede hacerlo con una consulta Count .

 Count query = Count.from(list); for (Count each: query) each.yield = "bat".equals(each.element); int number = query.result(); 

No quería que este caso fuera más difícil y lo hice con dos iteradores Tengo un HashMap con Apellido -> Nombre. Y mi método debe eliminar elementos con el nombre de stack.

 public static void removeTheFirstNameDuplicates(HashMap map) { Iterator> iter = map.entrySet().iterator(); Iterator> iter2 = map.entrySet().iterator(); while(iter.hasNext()) { Map.Entry pair = iter.next(); String name = pair.getValue(); int i = 0; while(iter2.hasNext()) { Map.Entry nextPair = iter2.next(); if (nextPair.getValue().equals(name)) i++; } if (i > 1) iter.remove(); } } 
 List lst = new ArrayList(); lst.add("Ram"); lst.add("Ram"); lst.add("Shiv"); lst.add("Boss"); Map mp = new HashMap(); for (String string : lst) { if(mp.keySet().contains(string)) { mp.put(string, mp.get(string)+1); }else { mp.put(string, 1); } } System.out.println("=mp="+mp); 

Salida:

 =mp= {Ram=2, Boss=1, Shiv=1}