2

I am struggling to sort a stream of strings (or list, if you prefer) in natural order ignoring a prefix. The prefix begins always with let and could be followed by any numbers (example, let12 or let3021)

Sample input:

let3 art zero
let2 own kit dig
let1 art can

Sample desired output:

let1 art can
let3 art zero
let2 own kit dig

So a simple idea that I have tried is to do the following:

list.stream().sorted();

But the numbers get in the way, producing the following output:

let1 art can
let2 own kit dig
let3 art zero

How can achieve this result in a simple way? The ideal solution would be a Comparator, or anything that I can use in a stream flow.

Note: my attempt to use the Comparator failed due the fact that the prefix could be of any length.

Thank you for your time.

Marco
  • 321
  • 3
  • 10

1 Answers1

3

You're answering your own question: With a comparator.

Comparator<String> marcosPrefixIgnoringComparison =
    (a, b) -> a.substring(4).compareTo(b.substring(4));

That's assuming that the prefix is defined as 'the first 4 characters'. If it's more 'The string let, and then any number of digits', you'd have to do something else. Possibly regexes:

Comparator<String> marcosPrefixIgnoringComparison =
    (a, b) -> a.replaceFirst("^let\\d+\\s+", "").compareTo(
      b.replaceFirst("^let\\d+\\s+", ""));

your question is not particularly clear about what 'prefix' means, here.

rzwitserloot
  • 85,357
  • 5
  • 51
  • 72
  • Hi, my bad, I have updated the question with more details about the prefix. My attempt with the comparator failed because the prefix could be of any length. I know really little about regex, I will dive deeper into your second answer and let you know. Thank you for your time – Marco Feb 11 '21 at 12:29
  • 2
    @Marco You could also use the static methods from `Comparator` to transform the strings prior to comparison. The argument to the `comparing` method is a `Function` transforming a string. This function is applied to both strings subject to the comparison. For example, `Comparator.comparing(str -> str.replaceFirst("^let\\d+\\s+", ""))` will yield the same result as `marcosPrefixIgnoringComparison` above. – MC Emperor Feb 11 '21 at 12:47
  • 2
    …and if you care for performance, you will compile the regex to a `Pattern` object once and keep it, to avoid parsing this nontrivial regex two times on every comparison. – Holger Feb 11 '21 at 13:12
  • Thank you Mc Emperor, that's even more concise and clean. That's good to know, Holger, thank you! – Marco Feb 12 '21 at 15:14