Given a String:
a - 11 h - 19 l - 18 d - 19
I need to sort its substrings first by numbers (in descending order) and then by letters, so that the result of the sort has the following form:
d - 19 h - 19 l - 18 a - 11
CodePudding user response:
To solve, the problem must be broken down into subproblems:
- Break down the input string into substrings
- Collect each substring into a list
- Create a comparator that compares the last (numeric) portion of the (sub)string and sorts them in descending order, and then by the beginning portion in ascending order
- Convert the list of substrings back into a string
Break down the input string into substrings
String regex = "\\w\\s-\\s\\d ";
String input = "a - 11 h - 19 l - 18 d - 19";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
matcher.toMatchResult().groupCount(); // this should return 4 (won't be used in final code)
Collect each substring into a list
List<String> strings = new ArrayList<>();
while (matcher.find()) {
strings.add(matcher.group());
}
The code above will iterate through all of the groups that matched the regex pattern and adds them to a list.
Create a comparator
Comparator<String> compareBySubstring = Comparator.comparing((String s) -> s.substring(s.indexOf(" -")))
.reversed().thenComparing((String s) -> s.substring(0, s.indexOf("-")));
List<String> newList = strings.stream().sorted(compareBySubstring).collect(Collectors.toList());
The comparator I created compares the last portion of the substrings (after the dash) and sorts them in descending order (reversed()
). Then, the intermediate result is sorted in ascending order from the beginning of the substring up to the dash. Basically it sorts the intermediate result in alphabetical order since the substrings start with a letter.
Convert the list of substrings back into a string
StringBuilder buffer = new StringBuilder();
newList.forEach(item -> {
buffer.append(item " "); // done to reinsert the space that separated each substring.
});
I created a test program to run this:
public class SortBySubstringDemo {
public static void main(String[] args) {
String regex = "\\w\\s-\\s\\d ";
String input = "a - 11 h - 19 l - 18 d - 19";
System.out.println("Input:\n" input);
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
List<String> strings = new ArrayList<>();
while (matcher.find()) {
strings.add(matcher.group());
}
Comparator<String> compareBySubstring = Comparator.comparing((String s) -> s.substring(s.indexOf(" -")))
.reversed().thenComparing((String s) -> s.substring(0, s.indexOf("-")));
List<String> newList = strings.stream().sorted(compareBySubstring).collect(Collectors.toList());
StringBuilder buffer = new StringBuilder();
newList.forEach(item -> {
buffer.append(item " ");
});
String output = buffer.toString().trim();
System.out.println("Output:\n" output);
}
}
Which results in the following:
Input:
a - 11 h - 19 l - 18 d - 19
Output:
d - 19 h - 19 l - 18 a - 11
CodePudding user response:
One alternative for your specific example is to use stream
:
public static String sort(String str) {
String[] arr = Arrays.stream(str.replaceAll(" - ", " ")
.split(" ")).filter(Predicate.not("-"::equals))
.toArray(String[]::new);
Comparator<Map.Entry<String, Integer>> comparator = Comparator
.comparingInt(Map.Entry<String, Integer>::getValue).reversed()
.thenComparing(Map.Entry::getKey);
return IntStream.range(0, arr.length).filter(i -> i % 2 == 0)
.mapToObj(i -> Map.entry(arr[i], Integer.parseInt(arr[i 1])))
.sorted(comparator).map(entry -> entry.getKey() " - " entry.getValue())
.collect(Collectors.joining(" "));
}
Then:
String str = "a - 11 h - 19 l - 18 d - 19";
String strSorted = sort(str);
System.out.println(strSorted);
Output:
d - 19 h - 19 l - 18 a - 11
CodePudding user response:
String s = "a - 11 h - 19 l - 18 d - 19";
record Pair(String string, int number) { }
System.out.println( new Scanner( s ).findAll( "(\\w)\\s-\\s(\\d )" )
.map( matchResult -> new Pair( matchResult.group( 1 ), Integer.parseInt( matchResult.group( 2 ) ) ) )
.sorted( Comparator.<Pair>comparingInt( Pair::number ).reversed().thenComparing( Pair::string ) )
.map( pair -> pair.string() " - " pair.number() )
.collect( Collectors.joining( " " ) ) );