Java-stream to filter list?

How to use the filter in java 8 stream to filter out complex List of objects. Suppose I have a class like this

public class InfoLite{
    private String right;
    List<Others> options;
    private String new;
}
//getter,setter and constructor
public class Others{    
    private String workId;
    private String work;
}
//getter,setter and constructor

I have an info object which is similar to this

List<InfoLite> info = new ArrayList<>();
List<Others> options = new ArrayList<>();
options.add(new Others(1,"game"))
options.add(new Others(2,"unit"))
options.add(new Others(3,"dest"))
List<Others> options2 = new ArrayList<>();
options.add(new Others(1,"console"))
options.add(new Others(2,"unit"))
List<Others> options3 = new ArrayList<>();
options.add(new Others(1,"zan"))
options.add(new Others(2,"zebvra"))
List<Others> options4 = new ArrayList<>();
options.add(new Others(1,"zan"))
options.add(new Others(2,"lon"))
options.add(new Others(3,"car"))
info.add(new Test("game,unit",options,"Florida"));
info.add(new Test("console",options2,"Florida"));
info.add(new Test("zebvra",options3,"Florida"));
info.add(new Test("lon",options4,"Florida"));

Here how can I filter the info list so that I can get a new list like this

List<InfoLite> newInfo = new ArrayList<>();

List<Others> options = new ArrayList<>();
options.add(new Others(1,"game"))
options.add(new Others(2,"unit"))

List<Others> options2 = new ArrayList<>();
options.add(new Others(1,"console"))

List<Others> options3 = new ArrayList<>();
options.add(new Others(2,"zebvra"))

List<Others> options4 = new ArrayList<>();
options.add(new Others(2,"lon"))

info.add(new Test("game,unit",options,"Florida"));
info.add(new Test("console",options2,"Florida"));
info.add(new Test("zebvra",options3,"Florida"));
info.add(new Test("lon",options4,"Florida"));

Here Others object is basically filtered i.e. filter only those object from the Others list whose have the matching value from right in info. If right in info is a comma-separated then split the right and check-in each Others list object and return the value.

What I tried is up to here but rest I am confused what to do next .

info.stream()
            .filter(option -> Arrays.stream(option.getRight().split(",")).collect(Collectors.toList()).contains(option.getOptions().stream().filter(Others :: getWork))))``


Answer

Assuming, you intend to print all Others instances that match one of the string in right value of InfoLite.

If that is the case the below snippet should help

System.out.println(info.stream()
                       .flatMap(infoLite -> infoLite.getOptions()
                                                    .stream()
                                                    .filter(option -> Arrays.stream(infoLite.getRight()
                                                                                            .split(","))
                                                                            .collect(Collectors.toSet())
                                                                            .contains(option.getWork())))
                       .collect(Collectors.toSet()));

Output:

[Others{workId=1, work='console'}, Others{workId=2, work='zebvra'}, Others{workId=1, work='game'}, Others{workId=2, work='unit'}, Others{workId=2, work='lon'}]

Note: I have made a couple of changes in the request program.

  • In the below snippet
    List<Others> options2 = new ArrayList<>();
    options.add(new Others(1, "console"));
    
    It should have been options2.add...
  • Assuming Test is a subclass of InfoLite
  • Introduced equals() and hashcode() for Others.
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Others others = (Others) o;
        return workId == others.workId &&
              Objects.equals(work, others.work);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(workId, work);
    }
    

UPDATE To retrieve the complete InfoList instances, the modified snippet is

info.forEach(infoLite -> {
    Set<String> rightSet = Arrays.stream(infoLite.getRight()
                                                 .split(","))
                                 .collect(Collectors.toSet());
    infoLite.getOptions()
            .removeIf(option -> !rightSet.contains(option.getWork()));
});

info.forEach(System.out::println);

It produces the below output

InfoLite{right='game,unit', newString='Florida', options=[Others{workId=1, work='game'}, Others{workId=2, work='unit'}]}
InfoLite{right='console', newString='Florida', options=[Others{workId=1, work='console'}]}
InfoLite{right='zebvra', newString='Florida', options=[Others{workId=2, work='zebvra'}]}
InfoLite{right='lon', newString='Florida', options=[Others{workId=2, work='lon'}]}

Leave a Reply

Your email address will not be published. Required fields are marked *