2010-03-08 18 views
47

pregunta es simple:intersección eficiente de dos lista <String> en Java?

tengo dos Lista

List<String> columnsOld = DBUtils.GetColumns(db, TableName); 
List<String> columnsNew = DBUtils.GetColumns(db, TableName); 

Y tengo que conseguir la intersección de éstos. ¿Hay una manera rápida de lograr esto?

+0

por qué no sólo tiene que utilizar para anidar bucles-? o un solo for-loop – Ungeheuer

+1

@JohnnyCoder en serio? – Pentium10

+0

funciona, ¿verdad? Desea encontrar dos elementos que coincidan, de esa manera funciona. el método de retención probablemente hace lo mismo, o similar, simplemente no lo ves. – Ungeheuer

Respuesta

96

Puede utilizar retainAll método:

columnsOld.retainAll (columnsNew); 
+8

Nota: para que esto funcione con otros objetos además de 'String', necesita por supuesto implementar' equals' y 'hashCode'. –

17

Desde retainAll no tocará la colección argumento, esto sería más rápido:

List<String> columnsOld = DBUtils.GetColumns(db, TableName); 
List<String> columnsNew = DBUtils.GetColumns(db, TableName); 

for(int i = columnsNew.size() - 1; i > -1; --i){ 
    String str = columnsNew.get(i); 
    if(!columnsOld.remove(str)) 
     columnsNew.remove(str); 
} 

La intersección serán los valores que quedan en columnsNew. Eliminar los valores ya comparados desde columnsOld reducirá el número de comparaciones necesarias.

+0

Pero su código definitivamente debe extraerse a un nuevo método separado porque no está claro desde este código qué hace. Y tampoco me hubiera negado una prueba de unidad adicional para este código. – Roman

+0

De acuerdo, una buena separación de métodos, nombres y pruebas unitarias siempre es la regla número uno. – bjornhol

+0

¿No debería este método agregar los elementos que no se pueden encontrar en las columnas Antiguo a las columnas Nuevo? Parece que esos elementos faltarán en el resultado. – Calon

6

¿Qué tal

private List<String> intersect(List<String> A, List<String> B) { 
    List<String> rtnList = new LinkedList<>(); 
    for(String dto : A) { 
     if(B.contains(dto)) { 
      rtnList.add(dto); 
     } 
    } 
    return rtnList; 
} 
+0

Esto no le dará el resultado correcto en todos los casos. Si B contiene elementos que no están contenidos en A, su método pierde esos elementos. – Calon

+6

Si B contiene elementos que no están contenidos en A, no hay necesidad de iterar sobre esos elementos porque estamos tratando de encontrar todos los elementos en A y B. – juan2raid

1

No es una forma agradable con las corrientes que pueden hacer esto en una línea de código y que es posible que dos listas que no son del mismo tipo que no es posible con el método containsAll afaik:

columnsOld.stream().filter(c -> columnsNew.contains(c)).collect(Collectors.toList()); 

Un ejemplo para listas con diferentes tipos. Si usted tiene un realtion entre foo y bar y se puede obtener una barra de objetos de foo de lo que puede modificar la secuencia:

List<foo> fooList = new ArrayList<>(Arrays.asList(new foo(), new foo())); 
List<bar> barList = new ArrayList<>(Arrays.asList(new bar(), new bar())); 

fooList.stream().filter(f -> barList.contains(f.getBar()).collect(Collectors.toList()); 
+0

'c -> columnsNew.contains (c)' lambda puede ser reescrito más conciso como una referencia de método: 'columnsNew :: contains'. – Bass

+0

¿no se ejecutará esto en O (n^2) vez? –

0

Si ponemos la segunda lista en un conjunto decir HashSet. Y simplemente itere sobre la primera lista para verificar si hay presencia en el conjunto y eliminarla si no está presente, su primera lista finalmente tendrá la intersección que necesita. Será mucho más rápido que retener todo o contiene en una lista. El énfasis aquí es usar un conjunto en lugar de una lista. Las búsquedas son O (1). firstList.retainAll (nuevo HashSet (secondList)) también funcionará.

0

usando retainAll si no les importa ocurrencias, de lo contrario el uso de N.intersection

a = N.asList(12, 16, 16, 17, 19); 
b = N.asList(16, 19, 107); 
a.retainAll(b); // [16, 16, 19] 
N.println(a); 

a = N.asList(12, 16, 16, 17, 19); 
b = N.asList(16, 19, 107); 
a = N.intersect(a, b); 
N.println(a); // [16, 19] 

N es una clase de utilidad en AbacusUtil

Cuestiones relacionadas