Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to filter objects with two lists using java 8 stream?

Tags:

java

java-8

I need to filter a list with a large amount of objects. For each of these objects I need to verify if any of the parameters contain one of the words that are in other lists. I have developed a method to do this, but it is taking too long, I would like to know if there is a more efficient way to do this.

The main idea could be written in sql for better understanding:

SELECT * FROM PROJECT P WHERE P.NAME LIKE "%JAVA%" OR P.NAME LIKE "%PASCAL%" OR P.PRODUCT LIKE "%JAVA%" OR P.PRODUCT LIKE "%PASCAL% OR. P.ADDRESS LIKE "%JAVA" OR P.ADDRESS LIKE "%PASCAL%";

In Java I wrote in this way:

private List<Projeto> filtraResultado(List<Projeto> projetosAssinados, String[] filtros){
List<Projeto> result = new ArrayList<Projeto>();
for(Projeto p: projetosAssinados) {
    if(existeFiltroBuscadoNosCamposDePesquisa(p.getDsProjeto(), filtros) ||
       existeFiltroBuscadoNosCamposDePesquisa(p.getNomeProjeto(), filtros) ||
       existeFiltroBuscadoNosCamposDePesquisa(p.getSetor(),filtros) ||
       existeFiltroBuscadoNosCamposDePesquisa(p.getUn(), filtros) ||
       existeFiltroBuscadoNosCamposDePesquisa(p.getProcessosModelados(),filtros)||
       existeFiltroBuscadoNosCamposDePesquisa(p.getServicosPrestados(),filtros) ||
       existeFiltroBuscadoNosCamposDePesquisa(p.getTecnologias(),filtros)||
       existeFiltroBuscadoNosCamposDePesquisa(p.getDetalhamento(),filtros)) {
            result.add(p);
    }

}
return result;

}

public boolean existeFiltroBuscadoNosCamposDePesquisa(String campoPesquisado,String[] filtros ){
if(campoPesquisado == null) {
    return false;
}
for(String f: filtros) {
    if(StringUtils.containsIgnoreCase(campoPesquisado, f.trim())) {
        return true;
    }
}
return false;

}

like image 833
oitathi Avatar asked Dec 31 '22 17:12

oitathi


1 Answers

The time complexity of your method can be improved by creating a Set<String> that contains the filter elements. This way, searching for a specific element will be O(1) instead of O(n):

private List<Projeto> filtraResultado(List<Projeto> projetosAssinados, String[] filtros) {
    Set<String> filterSet = Arrays.stream(filtros)
            .map(String::toLowerCase)
            .map(String::trim)
            .collect(Collectors.toSet());

    List<Projeto> result = new ArrayList<Projeto>();

    for (Projeto p : projetosAssinados) {
        boolean contained = Stream.of(p.getDsProjeto(), p.getNomeProjeto(),
                p.getSetor(), p.getUn(), p.getProcessosModelados(), 
                p.getServicosPrestados(), p.getTecnologias(), p.getDetalhamento())
            .filter(Objects::nonNull)
            .map(String::toLowerCase)
            .anyMatch(filterSet::contains);

        if (contained) {
            result.add(p);
        }
    }

    return result;
}

This should be significantly faster than your method for large inputs.

like image 187
Jacob G. Avatar answered Jan 08 '23 02:01

Jacob G.