A Map
for each sex
One quick and dirty approach would be a pair of Map
objects, for male and female each, where the key is a combination of your country and region while the value is an Integer
for the count of elements found.
Map< String , Integer > females = new TreeMap<>() ;
Map< String , Integer > males = new TreeMap<>() ;
Loop your collection of Registro
objects. For each Registro
object, get the country and region, and concatenate. Use some arbitrary character as a delimiter, such as a pipe |
(VERTICAL LINE), so you can later pull country and region apart (if need be). That string is the key in your map.
The value in the map, the Integer
object, is a count of Registro
objects for that country-region in that sex. See this Answer to learn about using Map::merge
to increment the map’s Integer
value using a method reference, Integer::sum
.
String key = registro.getCountry() + "|" + registro.getRegion() ;
if( registro.getSex().equals( "female" ) )
{
females.merge( key , 1 , Integer::sum ) ;
}
else if( registro.getSex().equals( "male" ) )
{
males.merge( key , 1 , Integer::sum ) ;
}
else // defensive programming
{
… handle error condition, illegal state.
}
To build your report, get a distinct set of all keys from both maps. Use a Set
for this, as a set eliminates duplicates. The Set
returned by Map::keySet
is actually a view onto the map rather than a separate collection. So we pass that set for one sex to constructor of a new and separate set. For the other sex, we call Set::addAll
. Thus we combine the two maps’ keys into a single distinct set.
We use a TreeSet
to keep the keys in natural order, matching the natural order used by the TreeMap
.
Set< String > keys = new TreeSet<>( females.keySet() ) ; // Build a fresh independent set from the set returned by `Map::keySet`.
keys.addAll( males.keySet() ) ; // Add in all the keys from the other map, automatically eliminating duplicates.
To build your report, loop the keys
set. For each key, call females.getKey
to get back a count, and call males.getKey
to get back a count. If either returns a null, report zero for that sex in that country-region.
for( String key : keys ){
Integer countFemales = Objects.requireNonNullElse( females.getKey( key ) , new Integer( 0 ) ) ;
Integer countMales = Objects.requireNonNullElse( males.getKey( key ) , new Integer( 0 ) ) ;
String output = key + " = " + countFemales + " females, " + countMales + " males." ;
}
China|Beigin = 13 females, 7 males.
The approach described here assumes your collection of Registro
objects is not being modified by another thread.
I expect there are other ways to solve your problem, likely more elegant no doubt. But this should get the job. I would use this approach myself.
By the way, here is a graphic table I made showing the attributes of various Map
implementations.
