Nilendra Mishra
Nilendra Mishra

Reputation: 13

Can we group same objects by different fields in java?

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

Answers (2)

Nowhere Man
Nowhere Man

Reputation: 19565

Sample implementation could be as follows:

  • collect list elements to a map: key - the list element, value - list of flights meeting the condition (self element or the element with departure equal to arrival)
  • retrieve collection of values and filter it
  • print the results
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

Felix Seifert
Felix Seifert

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

Related Questions