2

I have a string s, and an integer k (substring length), I am trying to write the function so that it finds the lexicographically smallest and largest substrings of length k. And It returns a String where samllest and largest substring combined with a newline.

Till now I solved the problem with below approach where I wrote same code to find both smallest and largest substring, however, I want to return both substring with single line of code with stream.

public static String getSmallestAndLargest(String s, int k) {
    String smallest = "";
    String largest = "";

    smallest = IntStream.range(0, s.length() - k + 1).mapToObj((value) -> s.substring(value, value + k))
            .collect(Collectors.minBy(String.CASE_INSENSITIVE_ORDER)).get();

    largest = IntStream.range(0, s.length() - k + 1).mapToObj((value) -> s.substring(value, value + k))
            .collect(Collectors.maxBy(String.CASE_INSENSITIVE_ORDER)).get();

    return smallest + "\n" + largest;
}

I appreciate any kind of suggestion as I am learning lambda and stream now.

So,how can I solve this simple problem elegantly?

Stefan Zobel
  • 3,182
  • 7
  • 28
  • 38
Amit
  • 1,540
  • 1
  • 15
  • 28
  • 2
    You would need to write a specific collector that would collect both the min and the max. Not sure why that would be more elegant than what you have now. You can concatenate all your lines in a single line, but that wwon't make your code more readable. Doing everything in a single line of code is not a desirable goal. – JB Nizet Oct 20 '18 at 14:36
  • thank you so much for your informative suggestion. – Amit Oct 20 '18 at 14:37

2 Answers2

2

I would just go old school and collect the sorted stream into a list and get the first and last element:

List<String> list = IntStream.range(0, s.length() - k + 1)
    .mapToObj((value) -> s.substring(value, value + k))
    .sorted(String.CASE_INSENSITIVE_ORDER)
    .collect(Collectors.toList());

smallest = list.get(0);
largest = list.get(list.size() - 1);
Sweeper
  • 213,210
  • 22
  • 193
  • 313
1

You can use the SummaryStatistics class of this answer

Then, the solution becomes:

SummaryStatistics<String> ss = IntStream.rangeClosed(0, s.length() - k)
    .mapToObj(value -> s.substring(value, value + k))
    .collect(SummaryStatistics.statistics(String.CASE_INSENSITIVE_ORDER));

String smallest = ss.getMin();
String largest  = ss.getMax();
Holger
  • 285,553
  • 42
  • 434
  • 765