I have a lists(states) of lists(cities) of lists(towns). How do I flatten the middle list(cities) and convert to a map(state's name) of map(town's name) of lists(towns)?
This question may look similar to the other question Java 3 level nested list to 3 level nested map, but they are not the same. This one, I need to flatten one of the lists.
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Data
@AllArgsConstructor
class Country {
private String name;
private List<State> states;
}
@Data
@AllArgsConstructor
class State {
private String name;
private List<City> cities;
}
@Data
@AllArgsConstructor
class City {
private String name;
private List<Town> towns;
}
@Data
@AllArgsConstructor
class Town {
private String name;
private String address;
private Integer population;
}
public static void main(String[]args) {
List<Town> countryAStateACityATownsList = new ArrayList();
countryAStateACityATownsList.add(new Town("CountryA-StateA-CityA-TownA", "addressOfCountryA-StateA-CityA-TownA", 100));
countryAStateACityATownsList.add(new Town("CountryA-StateA-CityA-TownB", "addressOfCountryA-StateA-CityA-TownB", 100));
countryAStateACityATownsList.add(new Town("CountryA-StateA-CityA-TownC", "addressOfCountryA-StateA-CityA-TownC", 100));
List<Town> countryAStateACityBTownsList = new ArrayList();
countryAStateACityBTownsList.add(new Town("CountryA-StateA-CityB-TownA", "addressOfCountryA-StateA-CityB-TownA", 100));
countryAStateACityBTownsList.add(new Town("CountryA-StateA-CityB-TownB", "addressOfCountryA-StateA-CityB-TownB", 100));
countryAStateACityBTownsList.add(new Town("CountryA-StateA-CityB-TownC", "addressOfCountryA-StateA-CityB-TownC", 100));
List<Town> countryAStateACityCTownsList = new ArrayList();
countryAStateACityCTownsList.add(new Town("CountryA-StateA-CityC-TownA", "addressOfCountryA-StateA-CityC-TownA", 100));
countryAStateACityCTownsList.add(new Town("CountryA-StateA-CityC-TownB", "addressOfCountryA-StateA-CityC-TownB", 100));
countryAStateACityCTownsList.add(new Town("CountryA-StateA-CityC-TownC", "addressOfCountryA-StateA-CityC-TownC", 100));
City cityA = new City("cityA", countryAStateACityATownsList);
City cityB = new City("cityB", countryAStateACityBTownsList);
City cityC = new City("cityC", countryAStateACityCTownsList);
List<City> countryAStateACitiesList = new ArrayList<>();
countryAStateACitiesList.add(cityA);
countryAStateACitiesList.add(cityB);
countryAStateACitiesList.add(cityC);
State stateA = new State("stateA",countryAStateACitiesList);
Country countryA = new Country("countryA", Collections.singletonList(stateA));
}
}
I want a map of states of towns. (so city list is flatten): state.name -> town.name -> town. I want to do something like destinationMap.get("stateA").get("CountryA-StateA-CityA-TownA") and that would give me the town instance that has the name "CountryA-StateA-CityA-TownA".
Please help, I have been trying to accomplish this by using stream, but not able to so far.
I have tried this:
countryA.getStates()
.stream()
.collect(Collectors.toMap(State::getName,
st-> st.getCities()
.stream()
.collect(Collectors.toMap(City::getName,
City::getTowns))));
This creates a map of state.name to city.name to towns. But this is not what I want.
I want a map of state.name to town.name to the town that has the same name.
I love functional parts of Java, here's what I did, seems to work the way you wanted to retrieve towns.
Map<String, Map<String, Town>> map =
countryA.getStates()
.stream()
.collect(Collectors.toMap(State::getName,
st -> st.getCities()
.stream()
.map(City::getTowns)
.flatMap(List::stream)
.collect(Collectors.toMap(Town::getName, Function.identity()))));
System.out.println(map.get("stateA").get("CountryA-StateA-CityA-TownA"));
Gives output
Town{name='CountryA-StateA-CityA-TownA', address='addressOfCountryA-StateA-CityA-TownA', population=100}
And watch out, you have duplicates in your example, I assumed there should not be duplicates of towns in different cities. Let me know if this is what you wanted!