-3

I have a task:

A sequence of positive integers numbers and a sequence of strings stringList are given. Get a new sequence of strings according to the following rule: for each value n from sequence numbers, select a string from sequence stringList that starts with a digit and has length n.

If there are several required strings in the stringList sequence, return the first; if there are none,then return the string "Not found"

For example:

input: {1, 3, 4}, {"1aa", "aaa", "1", "a"}
output: {"1", "1aa", "Not Found"}

My output:

[java.util.stream.ReferencePipeline$3@7f690630, 
java.util.stream.ReferencePipeline$3@edf4efb, 
java.util.stream.ReferencePipeline$3@2f7a2457]

My code:

(List<Integer> numbers, List<String> stringList) {
return numbers.stream()
        .map(Object::toString)
        .map(value -> (stringList.stream().filter(e -> (Character.isDigit(e.charAt(0)))).map(s -> {
            if (((Object) (s.length())).toString().equals(value)) return s;
            return "Not Found";
}))).map(Object::toString).collect(Collectors.toList());

help, please.

IFlex
  • 3
  • 2

1 Answers1

0

The following code using a regexp "\\d.*" to match a string starting with a digit should work.

Also, there's no need to convert an integer value to String and then convert this string back to int to match the length.

public static List<String> task(List<Integer> nums, List<String> strs) {
    return nums.stream()
        .map(i -> strs.stream()
                      //.filter(s -> s.length() == i && i > 0 && Character.isDigit(s.charAt(0)))
                      .filter(s -> s.length() == i && s.matches("\\d.*"))
                      .findFirst() // Optional<String>
                      .orElse("Not Found")
        )
        .collect(Collectors.toList());
}

Test

System.out.println(task(Arrays.asList(1, 3, 4), Arrays.asList("1aa", "aaa", "1", "a")));

Output:

[1, 1aa, Not Found]

Update

To get rid of nested streams, the list of strings should be converted into a filtered map where the length is a key and the first matching string is a value, and then use this map when streaming the list of integers:

public static List<String> taskFast(List<Integer> nums, List<String> strs) {
    Map<Integer, String> strByLength = strs
        .stream()
        .filter(s -> s.length() > 0 && Character.isDigit(s.charAt(0)))
        .collect(Collectors.toMap(
            String::length,
            s -> s,
            (s1, s2) -> s1 // keep the first match for the same length
        ));

    return nums.stream()
        .map(i -> strByLength.getOrDefault(i, "Not Found"))
        .collect(Collectors.toList());
}
Nowhere Man
  • 19,170
  • 9
  • 17
  • 42
  • Thanks a lot, code - working. p.s. Целый день сидел, никак не мог понять как два листа в одном потоке обработать. Почему-то в книжках этого нет. – IFlex Aug 29 '21 at 19:03
  • If you mean "stream" by "поток", for your current implementation nested streams (similar to nested loops) are used. It may be better to transform the string list into a map with the item length used as a key and then use this map to get appropriate value without nested streams, check the update. – Nowhere Man Aug 29 '21 at 20:42
  • Thanks, the first option suits me. I need to put all the code in one return statement. In addition, the first option is more illustrative for me. – IFlex Aug 31 '21 at 11:24
  • @iFlex, if the answer is helpful [please accept and/or upvote it](https://stackoverflow.com/help/someone-answers) – Nowhere Man Aug 31 '21 at 11:57