Reputation: 13
I want to group a single list into list of lists using conditional comparison between different field of the same object.
For Example: Say we have below class in java
class Flight {
String departureStation;
String arrivalStation;
}
Now I have List<Flight>
and I want them to group in List<List<Flight>>
if flight say, f1.arrivalStation == f2.departureStation
into one list.
for example, say we have Flight f1 = {departureStation = "Hyderabad", arrivalStation = "Mumbai"}
, Flight f2 = {departureStation = "Mumbai", arrivalStation = "Delhi"}
and Flight f3 = {departureStation = "Dubai", arrivalStation = "Newyork"}
then the final list should looks like,
since (f1.arrivalStation == f2.departureStation)
these two should get into one List
and for f3
since there is no match with given condition it'll be inside List
alone. and while grouping we should get List<List<Flight>>
with length of 2
, in which the first List
should have contained f1 and f2
and other list should contain only f3
Upvotes: 1
Views: 331
Reputation: 19565
Sample implementation could be as follows:
List<Flight> data = Arrays.asList(
new Flight("MOS", "MAD"),
new Flight("MAD", "BOS"),
new Flight("MAD", "JFK"),
new Flight("JFK", "MOS")
);
data.stream()
.collect(Collectors.toMap(x -> x,
x -> data.stream()
.filter(y -> x.equals(y) || y.dep().equals(x.arr()))
.collect(Collectors.toList())))
.values()
.stream()
.filter(e -> e.size() > 1)
.forEach(System.out::println);
output:
[MAD -> JFK, JFK -> MOS]
[MOS -> MAD, JFK -> MOS]
[MOS -> MAD, MAD -> BOS, MAD -> JFK]
Or a set of all airports may be retrieved and then the flight data could be selected by an airport - if it's mentioned as a departure or arrival:
data.stream()
.flatMap(x -> Stream.of(x.dep(), x.arr()))
.distinct()
.collect(Collectors.toMap(x -> x,
x -> data.stream()
.filter(y -> y.dep().equals(x)
|| y.arr().equals(x))
.collect(Collectors.toList()))
)
.values()
.stream()
.filter(e -> e.size() > 1)
.forEach(System.out::println);
output
[MOS -> MAD, JFK -> MOS]
[MOS -> MAD, MAD -> BOS, MAD -> JFK]
[MAD -> JFK, JFK -> MOS]
Upvotes: 0
Reputation: 602
I would create a stream out of List<Flight>
and use .filter()
to eventually collect it as a list. Then, you can do whatever you want to do with this list.
For the examples, we consider flights
to be of the type List<Flight
.
List<Flight> filteredFlights = flights.stream()
.filter(f -> f.arrivalStation.equals("Singapore"))
.collect(Collectors.toList());
This can then be added to a new List
which forms a list of lists.
List<List<Flight>> listOfLists = new ArrayList();
listOfLists.add(filteredFlights);
However, your example condition is slightly more complex and needs a loop within a loop which has a quadratic complexity of O(n²) with n as the number of flights in the list. You can choose between different loops, I combine the classical for
loop with the suggested stream solution (see above).
for(Flight f1 : flights) {
List<Flight> temporaryList = flights.stream()
.filter(f2 -> f1.arrivalStation.equals(f2.departureStation))
.collect(Collectors.toList());
listOfLists.add(temporaryList);
}
With some dynamic programming, the efficiency can be slightly improved.
(I ignored the missing getters and setters. For proper encapsulation, you might want to add them.)
Upvotes: 2