2012-02-06 36 views
8

tengo lista List<Custom> donde Custom es comoContar el número de elementos con propiedades

class Custom{ 
    public int id; 
    public String name; 
} 

Cómo obtener el número de artículos que tienen nombre de "Tom"? ¿Hay una manera más fácil que un bucle for?

+0

No hay 'Linq' para Java, aunque hay esto ... http://stackoverflow.com/questions/346721/linq-for-java-tool – xandercoded

Respuesta

2

No hay una solución más fácil con las colecciones estándar. Tienes que iterar sobre la lista y contar las ocurrencias del nombre.

1

O haga un seguimiento mientras agrega o elimina elementos de la lista. Esto podría tomar el lugar de un nombre de hash Name-> Count. Cuando al agregar un artículo incrementa el conteo de ese nombre, y cuando lo elimina, disminuye el recuento.

O itere sobre la colección con un bucle comprobando el nombre en cuestión.

Dependiendo del comportamiento de su aplicación, uno de estos métodos será más rápido, pero sin más información es difícil decir cuál.

1

Más fácil, probablemente no. Ahora podría almacenar sus objetos en un mapa < cadena, lista <personalizada> > en su lugar donde la clave es el nombre. Para obtener el número de elementos en nombre == "Tom" a continuación, puede simplemente hacer:

List<Custom> l = myMap.get("Tom"); 
int count = 0; 
if (l != null) { 
    count = l.size(); 
} 
1

También puede ordenar la lista antes de bucle, a continuación, utilizar divide y vencerás para encontrar coincidencias, entonces contar. Realmente depende de tus necesidades, como cuántos elementos? ¿Hay muchas inserciones después de una búsqueda? etc.

1

La forma en que se define ahora siempre requerirá un bucle sobre la lista.

Crear una índice secundario con un mapa de nombres a la lista de identificadores es una buena idea.

Una opción más sería asegurarse de que la lista esté ordenada por nombre, en cuyo caso todos los "Tom" se almacenarán uno al lado del otro. Entonces podrías encontrar el puño "Tom" en el tiempo O (log (n)) con una búsqueda binaria, y simplemente seguir contando desde allí hasta llegar a un "no" Tom o al final de la lista. La operación de inserción tendría O (n) complejidad ya que necesita mover todos los elementos después de la ubicación de inserción en una posición, así que considere esto cuidadosamente :-)

4

Personalmente, me gusta usar la Apache Commons Collection lib cuando puedo. (Pero el que está en sourceforge ya que usa genéricos) Le permite hacer cosas bastante elegantes como mapear listas o filtrar listas (de una manera similar). Acabaría escribiendo algo como esto:

int count = CollectionUtils.countMatches(myList, new Predicate<Custom>(){ 
    public boolean evaluate(Custom c){ return "Tom".equals(c.name); } 
} 

El único inconveniente es que desde Java no tiene funciones de primer orden, usted tiene que escribir pequeños objetos como esa instancia predicado. Sería más claro si pudieras escribir funciones anónimas. es decir, en Scala, sería la siguiente:

val myList = List("a", "a", "b", "c", "a") 
val c = myList.count{ "a".equals(_) } // is 3 
5

Si se va a filtrar por su nombre en varios lugares, y sobre todo si vas a la cadena que filtran con otros determinados en tiempo de ejecución, Google Guava predicados puede ayudarle a:

public static Predicate<Custom> nameIs(final String name) { 
    return new Predicate<Custom>() { 
     @Override public boolean apply(Custom t) { 
      return t.name.equals(name); 
     } 
    }; 
} 

Una vez que haya codificado ese predicado, el filtrado y el conteo solo tomarán una línea de código.

int size = Collections2.filter(customList, nameIs("Tom")).size(); 

Como se puede ver, la construcción de un prolijo (estilo funcional) predicado no siempre será más fácil de leer, más rápido o ahorrar líneas de código en comparación con bucles (estilo imperativo). De hecho, Guava documentation establece explícitamente que el estilo imperativo debe usarse de manera predeterminada. Pero los predicados son una buena herramienta para tener de todos modos.

0

¿Qué tal esto? :

package test; 

import java.util.ArrayList; 
import java.util.Collection; 
import java.util.HashMap; 
import java.util.Map; 

public class CustomArrayBuilder extends ArrayList<Custom> { 

    Map<String, Integer> namesMap = new HashMap<String, Integer>(); 

    public CustomArrayBuilder(Collection<? extends Custom> c) { 
     super(c); 
     this.prepareAddAll(c); 
    } 

    public int getDifferentNamesAmount() { 
     return this.namesMap.size(); 
    } 

    public int getNameAmount(String name) { 
     Integer integer = this.namesMap.get(name); 
     return (integer != null) ? integer : 0; 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public Custom set(int index, Custom element) { 
     Custom custom = super.set(index, element); 
     prepareSet(custom, element); 
     return custom; 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public boolean add(Custom e) { 
     this.prepareAdd(e); 
     return super.add(e); 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public void add(int index, Custom element) { 
     this.prepareAdd(element); 
     super.add(index, element); 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public Custom remove(int index) { 
     Custom custom = super.remove(index); 
     this.prepareRemove(custom); 
     return custom; 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public void clear() { 
     super.clear(); 
     this.namesMap.clear(); 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public boolean addAll(Collection<? extends Custom> c) { 
     this.prepareAddAll(c); 
     return super.addAll(c); 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public boolean addAll(int index, Collection<? extends Custom> c) { 
     this.prepareAddAll(c); 
     return super.addAll(index, c); 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public boolean remove(Object o) { 
     if (super.remove(o)) { 
      this.prepareRemove((Custom) o); 
      return true; 
     } else { 
      return false; 
     } 
    } 

    private void prepareSet(Custom oldCustom, Custom newCustom) { 
     if (oldCustom != null && !oldCustom.name.equals(newCustom.name)) { 
      this.prepareRemove(oldCustom); 
      this.prepareAdd(newCustom); 
     } 
    } 

    private void prepareAdd(Custom custom) { 
     if (custom != null) { 
      Integer integer = this.namesMap.get(custom.name); 
      this.namesMap.put(custom.name, (integer != null) ? integer + 1 : 1); 
     } 
    } 

    private void prepareAddAll(Collection<? extends Custom> c) { 
     for (Custom custom : c) { 
      this.prepareAdd(custom); 
     } 
    } 

    private void prepareRemove(Custom custom) { 
     if (custom != null) { 
      Integer integer = this.namesMap.get(custom.name); 
      this.namesMap.put(custom.name, (integer != null && integer > 0) ? integer - 1 : 0); 
     } 
    } 
} 

Uso:

package test; 

import java.util.ArrayList; 
import java.util.List; 

public class Test { 

    public static void main(String[] args) { 

     List<Custom> list = new ArrayList<Custom>() {{ 
      add(new Custom("A")); 
      add(new Custom("B")); 
      add(new Custom("C")); 
      add(new Custom("A")); 
      add(new Custom("A")); 
      add(new Custom("B")); 
     }}; 

     CustomArrayBuilder customs = new CustomArrayBuilder(list); 
     Custom custom = new Custom("B"); 
     customs.add(custom); 
     customs.add(custom); 
     customs.remove(custom); 
     customs.remove(custom); 
     customs.remove(custom); 

     System.out.println("A: " + customs.getNameAmount("A")); 
     System.out.println("B: " + customs.getNameAmount("B")); 
     System.out.println("C: " + customs.getNameAmount("C")); 
     System.out.println("Z: " + customs.getNameAmount("Z")); 
     System.out.println("Total different names: " + customs.getDifferentNamesAmount()); 
    } 
} 

Salida:

A: 3 
B: 2 
C: 1 
Z: 0 
Total different names: 3 

Podría ser muy útil cuando se utiliza con frecuencia sus operaciones de recuento. Nota: No debe cambiar el nombre del objeto personalizado, debe ser definitiva:

package test; 

class Custom { 
    public int id; 
    final public String name; 

    public Custom(String name) { 
     this.name = name; 
    } 
} 

O usted tiene que hacer algo con la lista también, cuando se cambia el nombre de un objeto personalizado en la lista.

7

Esto ahora se puede hacer fácilmente con Java 8 streams — no se requieren bibliotecas adicionales.

List<Custom> list = /*...*/; 
long numMatches = list.stream() 
         .filter(c -> "Tom".equals(c.name)) 
         .count(); 
+0

Debe tenerse en cuenta que el valor después de c -> es siempre un booleano – galv

0

Puede utilizar count() de Eclipse Collections.

MutableList<Custom> customList = Lists.mutable.empty(); 
int count = customList.count(each -> "Tom".equals(each.getName())); 

Si no puede cambiar CustomList de List:

List<Custom> customList = new ArrayList<>(); 
int count = ListAdapter.adapt(customList).count(each -> "Tom".equals(each.getName())); 

Si usted tiene un método que comprueba un nombre también se puede utilizar countWith():

MutableList<Custom> customList = Lists.mutable.empty(); 
int count = customList.countWith(Custom::isNamed, "Tom"); 

class Custom 
{ 
    public int id; 
    public String name; 

    public boolean isNamed(String nameToCheck) 
    { 
     return nameToCheck.equals(this.name); 
    } 
} 

Nota: I soy colaborador de Eclipse Collections.

Cuestiones relacionadas