Stream grouping by first 3 chars

nopens :

I have a list of phone numbers, which I used to group by national (German numbers) / international (rest of the world). Example list looks like:

List<String> list = new ArrayList<>();
list.add("+4969123");
list.add("+4989123");
list.add("+4930123");
list.add("+4365013");
list.add("+4369923");
list.add("+4365023");
list.add("+4176123");
list.add("+4178123");
list.add("+4179123");
list.add("+447782");
list.add("+447903");
list.add("+447701");

and a method to group by the prefix "+49"

public static Map<Boolean,List<String>> national_International_Map(List<String> list){
    return list.stream().collect(Collectors.groupingBy(s -> s.startsWith("+49")));
}

then I cann call the method with true or false to get the numbers separted to national/ international

List<String> nationalNums      = national_International_Map(list).get(true);
List<String> internationalNums = national_International_Map(list).get(false);

But now the requirements have changed and I have to group the numbers by country. At the moment there are only four countries. But more may be added later. For this I have thought about the following, but it is complicated if I have to group more countries.

public static Map<Boolean,List<String>> countryMap(List<String> list, String country){
    switch(country){
        case "de": return list.stream().collect(Collectors.groupingBy(s -> s.startsWith("+49")));
        case "at": return list.stream().collect(Collectors.groupingBy(s -> s.startsWith("+43")));
        case "ch": return list.stream().collect(Collectors.groupingBy(s -> s.startsWith("+41")));
        case "uk": return list.stream().collect(Collectors.groupingBy(s -> s.startsWith("+44")));
        default:   return null;
    }
}

and call it like:

List<String> ukNums = countryMap(list,"uk").get(true);
List<String> chNums = countryMap(list,"ch").get(true);

Can somebody tell me how I should do it best - maybe without extending the switch block all the time? I would like to have something like :

List<String> ukNums = countryMap(list).get("uk");
Joni :

If you define a getCountryFromPhone method, you can group phone numbers by their country with the groupingBy method you've been using so far:

Map<String, List<String>> groupedPhones = list.stream().collect(Collectors.groupingBy(s -> getCountryFromPhone(s)));

Then you can get the UK phone numbers the way you want: groupedPhones.get("uk")

Now, what does getCountryFromPhone look like? It should return the country code for a phone number, so the following will work for starters.

static Map<String,String> phoneMap = Map.of(
    "+49", "de",
    "+43", "at",
    "+41", "ch",
    "+44", "uk");

private static String getCountryFromPhone(String s) {
    return phoneMap.getOrDefault(s.substring(0, 3), "unknown");
}

Later on, you may need to add support for countries with phone country codes of different length. This is not a trivial thing, and there are libraries like libphonenumber to help with this. You would just make your getCountryFromPhone call the appropriate method in the library.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=384964&siteId=1