Home > Software design >  How to map values in a List<Integer> to elements in a List<String> using Stream Api with
How to map values in a List<Integer> to elements in a List<String> using Stream Api with

Time:08-22

I have the following task.

We have two lists: the first one integerList of type Integer and the second stringList of type String.

The goal is:

  • For each value n from integerList select a string from stringList that starts with a digit and has a length n;
  • If there are several required strings in the stringList, select the first one;
  • If there's no required string, place "Not found" as an appropriate element.

My code:

public static List<String> foo(List<Integer> integerList, List<String> stringList) {
    return integerList.stream()
        .map(integer -> stringList.stream()
                .filter(...) // not sure what to use here
                .findFirst()
                .orElse("Not found"))
        .collect(Collectors.toList());
}

I'm not sure what should I use in the filter.

Input:

integerList = [1, 3, 4]
stringList = ["1aa", "aaa", "1", "a"]

Desired output:

["1", "1aa", "Not Found"]

CodePudding user response:

You can generate from the list of strings a map Map<Integer,String>, which associates string length with the first string in a list having this length.

And then process the contents of the list of integers.

To filter only those strings that start with a digit, we can use the following regular expression "^//d.*", which would match any string that has a digit as its first character, followed by zero or more characters.

List<Integer> integerList = List.of(1, 3, 4);
List<String> stringList = List.of("1aa", "aaa", "1", "a");
        
Map<Integer, String> strByLength = stringList.stream()
    .filter(str -> str.matches("^//d.*")) // string starts with a digit
    .collect(Collectors.toMap(
        String::length,        // key
        Function.identity(),   // value
        (left, right) -> left  // pick the first encountered value
    ));
    
List<String> result1 = integerList.stream()
    .map(i -> strByLength.getOrDefault(i, "Not Found"))
    .toList();
    
System.out.println(result1);

Output:

[1, 1aa, Not Found]

It can also be done by creating a nested stream inside map() operation, i.e. in the way that tried to achieve it. For that, you need to use the following predicate inside the filter() applied before findFirst():

.filter(str -> str.length() == integer)

Note that such solution is less performant than the first one, which uses Map, because it requires to iterate over the list of string as many times as there are elements in the list of integers. Meanwhile, the map-based approach requires only a single iteration.

CodePudding user response:

Java Strings have a length() method you can use to check the number of characters.

For the first character check you can use the charAt(index) method also available in String.

You can combine this with the Character.isDigit(char) method to check for the requirement.

I guess a solution could look something like this

public static List<String> f(List<Integer> integerList, List<String> stringList) {
    return integerList.stream().map(
        integer -> stringList.stream()
                .filter(s -> s.length() == integer)
                .filter(s -> Character.isDigit(s.charAt(0)))
                .findFirst().orElse("Not found")
    ).collect(Collectors.toList());
}
  • Related