0

I have two lists (trains, wagons). I only want to have the trains which have wagons from the "wagon"-list and store them in the "finalList".

List<train> trains;
List<wagon> wagons;

List<train> finalList

A train has the attributes Id, Color, Wagon. A wagon has the attributes Id, Seats, Type. Both lists has several entries.

List<train> finalList= trains.stream().filter(tr-> tr.getWagons.retainAll(wagons)).collect(Collectors.toList());

My finalList is every time empty and i don't know why. Same with containsAll(). I also tried something like that:

finalList = trains.stream().filter(tr -> wagons.stream().anyMatch(wg -> tr.getWagons().foreach(trWg -> trWg.getId().equals(wg.getId()))))

But I was unable to filter the trains list by wagons from the wagon list

6
  • Don't you want .isEmpty()? containsAll would mean the train has all the wagons. retainAll ought to work (although modify!) - is there a dodgy equals method? Commented Mar 1, 2020 at 20:26
  • No, I want to filter the trains list, so that I have all trains with wagons from the wagon list. But I get no matching entries Commented Mar 1, 2020 at 20:29
  • Oh I see. Is .getWagons. a method (one that copies the List)? finalList being empty implies retainAll returns false, i.e. no modification. Even for a train with no wagons? Otherwise I would expect an equals method always returning false. Commented Mar 1, 2020 at 20:38
  • Post the POJO for each please. Commented Mar 1, 2020 at 20:41
  • Note that a wagon from the list and another one as train's attribute might be different instances (different @). It all depends on how the two wagons have been instantiated, in case the list is filled with wagons from train, then you can compare both objects, otherwise you should implement you own comparator method. Commented Mar 1, 2020 at 20:45

2 Answers 2

1

So first of all in the description You say that

A train has the attributes Id, Color, Wagon.

But, later in the example:

finalList = trains.stream() .filter(tr -> wagons.stream() .anyMatch(wg ->tr.getWagons() .foreach(trWg -> trWg.getId().equals(wg.getId()))));

Therefore I assume that the first one was true, and for some reason your train can have only one wagon for now

There are several solutions to this "problem":

First and the cleanest method in my opinion:

List<Wagon> wagons = new ArrayList<>();

    wagons.add(new Wagon(0L, new ArrayList<>(), "0"));
    wagons.add(new Wagon(1L, new ArrayList<>(), "1"));

    List<Train> trains = new ArrayList<>();

    trains.add(new Train(0L, wagons.get(0), "Yellow"));
    trains.add(new Train(1L, wagons.get(1), "Blue"));
    trains.add(new Train(2L, new Wagon(12L, new ArrayList<>(), "not in wagon list"), "Blue"));


    List<Train> finalList = trains.stream().
            filter(train -> wagons.contains(train.getWagon()))
            .collect(Collectors.toList());

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

And ofc POJO'S

@Getter
@AllArgsConstructor
@ToString
class Train {
    private Long id;
    private Wagon wagon;
    private String color;
}

@Getter
@ToString
@AllArgsConstructor
@EqualsAndHashCode
class Wagon {
    private Long id;
    private List<String> seats;
    private String type;
}

But you have to remember here to implement equals() for Wagon

Second method without the need of implementing the equals() is:

  List<Train> finalList2 = trains.stream()
            .filter(train -> wagons
                    .stream()
                    .anyMatch(wagon -> wagon.getId().equals(train.getWagon().getId())))
            .collect(Collectors.toList());

Now assume that your train can have more than one wagon...

@Getter
@AllArgsConstructor
@ToString
class Train {
    private Long id;
    private List<Wagon> wagons;
    private String color;
}

And the code:

List<Wagon> wagons = new ArrayList<>();

wagons.add(new Wagon(0L, new ArrayList<>(), "0"));
wagons.add(new Wagon(1L, new ArrayList<>(), "1"));
List<Wagon> wagons2 = new ArrayList<>();

wagons2.add(new Wagon(11L, new ArrayList<>(), "11"));
wagons2.add(new Wagon(12L, new ArrayList<>(), "12"));

List<Train> trains = new ArrayList<>();

trains.add(new Train(0L, wagons,"Yellow"));
trains.add(new Train(1L, wagons2, "Blue"));
trains.add(new Train(2L, Arrays.asList(new Wagon(132L, new ArrayList<>(),"not in wagon list")), "Blue"));

   List<Train> finalList3 = trains.stream()
            .filter(train -> train.getWagons().containsAll(wagons))
            .collect(Collectors.toList());

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

As long as you assume, that you are interested only in trains containing exact set of wagons. And equals() is necessary for this method too!

Sign up to request clarification or add additional context in comments.

Comments

1

I have no idea what your POJO's are since you didn't post them so all I can do is assume from your list of attributes that you've posted. This is one way to do it.

All we're doing is we're looping through all trains and filtering by whether or not the List of Wagon objects contains a wagon with the same id as the wagon from the train. We're then collecting to a List.

    List<Train> trains = Arrays.asList(
            new Train(1, 0, new Wagon(0, 1, 0)), 
            new Train(2, 0, new Wagon(1, 1, 0)));

    List<Wagon> wagons = Arrays.asList(new Wagon(0, 1, 0));

    List<Train> trainsFromWagons = trains.stream().filter(train -> wagons.stream().anyMatch(wagon -> train.wagon.id == wagon.id))
            .collect(Collectors.toList());

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.