Trinithy2000 Trinithy2000 - 1 year ago 42
Java Question

Split List<yourClass> to List<List<yourClass>> by condition of yourClass java 8

Suppose a list of objects (yourClass) that we have to divide into a list of lists and we do not want to cross the same to generate it.

We also want to reuse the class generically.

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class ListOfList {

public static <T> List<List<T>> generateSuperList(List<T> lista, Class<T> clazz, String field ){
List<List<T>> superLista = new ArrayList<List<T>>();
return generateSuperListPrivate(lista, superLista, clazz, field);
}
private static <T> List<List<T>> generateSuperListPrivate(List<T> lista, List<List<T>> superLista, Class<T> clazz,
String field) {

superLista.add(filteredList(lista, clazz, field));

if (lista.size() > 0)
generateSuperListPrivate(lista, superLista, clazz, field);

return superLista;
}

private static <T> List<T> filteredList(List<T> lista, Class<T> clazz, String field) {

List<T> aux = new ArrayList<T>();
if (lista.size() > 0) {
try {
Predicate<T> first = p -> GetPropValue(p, field).equals(GetPropValue(lista.get(0), field));
aux = lista.stream().filter(first).collect(Collectors.toList());
if (aux.size() > 0) {
lista.removeAll(aux);
}
} catch (Exception e) {
e.printStackTrace();
}
}
return aux;
}

private static <T> Object GetPropValue(Object src, String propName) {
Object o = null;
try {
Method method = src.getClass().getMethod("get" + propName, new Class[] {});
o = method.invoke(src);

} catch (Exception e) {
e.printStackTrace();
}

return o;
}

}


An example of how to use this class.

public class Main {
public static void main(String[] args) {

List<Person> lista = new ArrayList<Person>();
lista.add(new Person(1, "S1"));
lista.add(new Person(1, "S2"));
lista.add(new Person(1, "S3"));
lista.add(new Person(1, "S4"));
lista.add(new Person(2, "E3"));
lista.add(new Person(2, "E4"));
lista.add(new Person(2, "E5"));
lista.add(new Person(3, "F1"));
lista.add(new Person(1, "S5"));
lista.add(new Person(2, "E1"));
lista.add(new Person(2, "E2"));

List<Person> lista2 = new ArrayList<Person>();
lista2.addAll(lista);
try {
List<List<Person>> lista3 = ListOfList.generateSuperList(lista2, Person.class, "Id");
System.out.println(lista3);
} catch (SecurityException e) {
// TODO Bloque catch generado automáticamente
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}


and the class Person

public class Person {

private Integer id;
private String nombre;

public Person(Integer id, String nombre) {
super();
this.id = id;
this.nombre = nombre;
}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getNombre() {
return nombre;
}

public void setNombre(String nombre) {
this.nombre = nombre;
}


Im New with java 8. I'st works but, I think there are other ways yo made this more easly. Any sugesttions?

Answer Source

Collectors.groupingBy does exactly this. It takes a type T and a Function<T, K> which takes each t and gets it's "grouping key". It then generates a Map<K, List<T>> which groups all t with the same k into a List.

In your example:

final Map<Integer, List<Person>> grouped = lista.stream().collect(Collectors.groupingBy(Person::getId));

If you want a List<List<Person>> then you can simply copy:

final List<List<Person>> lista3 = new ArraysList<>(grouped.values());

If you want to be fancy you can do that on one line; it doesn't save you anything though:

final List<List<Person>> lista3 = lista.stream().collect(collectingAndThen(groupingBy(Person::getId), map -> new ArrayList<>(map.values())));

Your ListOfList utility class is very inefficient and does not seem to serve a useful purpose - consider getting rid of it.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download