I have this block of code.
I need to return hashmap that has the gender as key,and another hashmaap value the second hash map has yearofbirth as key and arraylist of all people with that saame yearofbear in it .
wrote this code but when i print it prints duplicates of the same customer and employees
public HashMap<Gender, HashMap <Integer, ArrayList<Person>>> personsByGenderAndYearOfBirth() {
ArrayList<Person> Males=new ArrayList<Person>();
ArrayList<Person> Females=new ArrayList<Person>();
HashMap<Integer,ArrayList<Person>> AccBirthDateMale=new HashMap<>();
HashMap<Integer,ArrayList<Person>> AccBirthDateFemale=new HashMap<>();
HashMap<Gender, HashMap<Integer,ArrayList<Person>>> AccGender=new HashMap<>();
for(HashMap.Entry<String, Customer> entry : allCustomers.entrySet())
{
{
switch(entry.getValue().getGender())
{
case M:
Males.add(entry.getValue());
AccBirthDateMale.put(entry.getValue().getYearOfBirth(),Males);
break;
case F:
Females.add(entry.getValue());
AccBirthDateFemale.put(entry.getValue().getYearOfBirth(),Females);
break;
}
}
}
AccGender.put(Gender.F, AccBirthDateFemale);
AccGender.put(Gender.M, AccBirthDateMale);
for(HashMap.Entry<String, Employee> entry : allEmployees.entrySet())
{
switch(entry.getValue().getGender())
{
case M:
Males.add(entry.getValue());
AccBirthDateMale.put(entry.getValue().getYearOfBirth(),Males);
break;
case F:
Females.add(entry.getValue());
AccBirthDateFemale.put(entry.getValue().getYearOfBirth(),Females);
break;
}
}
AccGender.put(Gender.F, AccBirthDateFemale);
AccGender.put(Gender.M, AccBirthDateMale);
System.out.println(AccBirthDateMale.toString());
System.out.println(AccGender.toString());
return AccGender;
}
The issue is that you add a person to its gender list, no matter the year, then use this list of the person's year, so every year ends up pointing to the same and unique genderlist
Males.add(entry.getValue());
AccBirthDateMale.put(entry.getValue().getYearOfBirth(), Males);
You add the outer mapping directly at initialisation of the resulting map
Iterate directly over the values of the map, then you gendered map per year, and add the mapping if it's missing, add the person to its year, and finally year
Map<Gender, Map<Integer, List<Person>>> result = Map.of(Gender.M, accBirthDateMale, Gender.F, accBirthDateFemale);
for (Person person : allCustomers.values()) {
switch (person.getGender()) {
case M:
if(!accBirthDateMale.containsKey(person.getYearOfBirth())){
accBirthDateMale.put(person.getYearOfBirth(), new ArrayList<>());
}
accBirthDateMale.get(person.getYearOfBirth()).add(person);
break;
case F:
if(!accBirthDateFemale.containsKey(person.getYearOfBirth())){
accBirthDateFemale.put(person.getYearOfBirth(), new ArrayList<>());
}
accBirthDateFemale.get(person.getYearOfBirth()).add(person);
break;
}
}
result.put(Gender.M, accBirthDateMale);
result.put(Gender.F, accBirthDateFemale);
The previous code is quite verbose, and map offers nice methods to handle the missing-key case (computeIfAbsent
)
public static Map<Gender, Map<Integer, List<Person>>> personsByGenderAndYearOfBirth() {
Map<Gender, Map<Integer, List<Person>>> result = Map.of(Gender.M, new HashMap<>(), Gender.F, new HashMap<>());
for(Collection<? extends Person> people : List.of(allCustomers.values(), allEmployees.values())){
for (Person person : people) {
result.get(person.getGender()).computeIfAbsent(person.getYearOfBirth(), k -> new ArrayList<>()).add(person);
}
}
return result;
}
Using Streams
public static Map<Gender, Map<Integer, List<Person>>> personsByGenderAndYearOfBirthBis() {
return Stream.of(allCustomers.values(), allEmployees.values())
.flatMap(Collection::stream)
.collect(Collectors.groupingBy(Person::getGender, Collectors.groupingBy(Person::getYearOfBirth, Collectors.toList())));
}