猿问

字符串和数字的范围分组列表

我有一个看起来像这样的列表


String[] lst = {BB,2,1,3,AA,DD,A3,A1,EE,A2,4);


我需要对该列表进行分组和排列,但遇到了麻烦,因此需要找到类似的东西


结果:(1-4),(A1-A3),(AA-BB),(DD-EE)


我想出的代码是这样的


Map<Character, List<String>> collect;


collect = Arrays.stream(str).

flatMap(s -> Stream.of(s.split("[^a-zA-Z0-9]"))).

filter(s -> !s.trim().isEmpty()).

sorted().

collect(Collectors.groupingBy(s -> s.charAt(0)));

但它按第一个字母分组,这意味着 AA 与 A1-A3 分组,依此类推。它不是那么微不足道的分组,我将不胜感激任何帮助。


呼唤远方
浏览 155回答 3
3回答

慕尼黑8549860

这是我的解决方案。AdjacentAwareComparator只要它在其价值空间中正确实施,这将适用于任何给定的情况。以下comparator是您定义的值空间。如果您不需要所有元素,您可以很容易地getRanges接受一个而不是数组,或者只存储范围的第一个和最后一个:Listimport static java.lang.Character.isDigit;import java.util.ArrayList;import java.util.Arrays;import java.util.Comparator;import java.util.List;public class Main {&nbsp; &nbsp; /**&nbsp; &nbsp; &nbsp;* Marker interface.&nbsp; &nbsp; &nbsp;*&nbsp;&nbsp; &nbsp; &nbsp;* Implementors MUST adhere to all contracts of Comparator, and MUST return -1 or 1 if and only if&nbsp; &nbsp; &nbsp;* the compared values are adjacent to one another within the set of all possible values.&nbsp; &nbsp; &nbsp;*/&nbsp; &nbsp; @FunctionalInterface public interface AdjacentAwareComparator<T> extends Comparator<T> {};&nbsp; &nbsp; /**&nbsp; &nbsp; &nbsp;* Assumes the input is valid in the defined value space.&nbsp; &nbsp; &nbsp;*&nbsp;&nbsp; &nbsp; &nbsp;* Sort order: Digit (natural), Alpha+Digit (by alpha, then by digit), Alpha+Alpha (natural)&nbsp; &nbsp; &nbsp;*/&nbsp; &nbsp; private static AdjacentAwareComparator<String> comparator = (x, y) -> {&nbsp; &nbsp; &nbsp; &nbsp; // uses 2 and -2 to compare values as non-adjacent&nbsp; &nbsp; &nbsp; &nbsp; if (x == null) return (y == null) ? 0 : -2;&nbsp; &nbsp; &nbsp; &nbsp; if (y == null) return 2;&nbsp; &nbsp; &nbsp; &nbsp; // both are not null...&nbsp; &nbsp; &nbsp; &nbsp; if (x.isEmpty()) return y.isEmpty() ? 0 : -2;&nbsp; &nbsp; &nbsp; &nbsp; if (y.isEmpty()) return 2;&nbsp; &nbsp; &nbsp; &nbsp; // both are at least length 1...&nbsp; &nbsp; &nbsp; &nbsp; char x1 = x.charAt(0), y1 = y.charAt(0);&nbsp; &nbsp; &nbsp; &nbsp; if (isDigit(x1)) return isDigit(y1) ? (x1 - y1) : -2;&nbsp; &nbsp; &nbsp; &nbsp; if (isDigit(y1)) return 2;&nbsp; &nbsp; &nbsp; &nbsp; // both start with letters...&nbsp; &nbsp; &nbsp; &nbsp; int d1 = x1 - y1; // delta between first chars&nbsp; &nbsp; &nbsp; &nbsp; char x2 = x.charAt(1), y2 = y.charAt(1);&nbsp; &nbsp; &nbsp; &nbsp; if (isDigit(x2)) return isDigit(y2) ? ((d1 == 0) ? (x2 - y2) : (d1 * 2)) : -2;&nbsp; &nbsp; &nbsp; &nbsp; if (isDigit(y2)) return 2;&nbsp; &nbsp; &nbsp; &nbsp; // the strings are double letters (eg. 'AA' and 'BB')&nbsp; &nbsp; &nbsp; &nbsp; return d1;&nbsp; &nbsp; };&nbsp; &nbsp; public static <T> List<List<T>> getRanges(T[] arr, AdjacentAwareComparator<T> comp) {&nbsp; &nbsp; &nbsp; &nbsp; if (arr.length == 0) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return new ArrayList<>();&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; List<List<T>> ranges = new ArrayList<>();&nbsp; &nbsp; &nbsp; &nbsp; List<T> range = new ArrayList<>();&nbsp; &nbsp; &nbsp; &nbsp; // sort using the custom Comparator&nbsp; &nbsp; &nbsp; &nbsp; Arrays.sort(arr, comp);&nbsp; &nbsp; &nbsp; &nbsp; T prev = arr[0];&nbsp; &nbsp; &nbsp; &nbsp; range.add(prev);&nbsp; &nbsp; &nbsp; &nbsp; // iterate through the sorted array&nbsp; &nbsp; &nbsp; &nbsp; for (int i = 1; i < arr.length; i++) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; T curr = arr[i];&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int d = comp.compare(prev, curr);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (d < -1 || 1 < d) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // prev and curr are not adjacent nor equal, so start a new range&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ranges.add(range);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; range = new ArrayList<>();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; range.add(curr);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; prev = curr;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; ranges.add(range);&nbsp; &nbsp; &nbsp; &nbsp; return ranges;&nbsp; &nbsp; }&nbsp; &nbsp; public static void main(String[] args) {&nbsp; &nbsp; &nbsp; &nbsp; String[] arr = {"4","1","BB","ZZ","A1","5","A5","FF","3","B2","A2","B1","AA"};&nbsp; &nbsp; &nbsp; &nbsp; for (List<String> range : getRanges(arr, comparator)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println("{" + String.join(", ", range) + "}");&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; // prints:&nbsp; &nbsp; &nbsp; &nbsp; //&nbsp; &nbsp;{1}&nbsp; &nbsp; &nbsp; &nbsp; //&nbsp; &nbsp;{3, 4, 5}&nbsp; &nbsp; &nbsp; &nbsp; //&nbsp; &nbsp;{A1, A2}&nbsp; &nbsp; &nbsp; &nbsp; //&nbsp; &nbsp;{A5}&nbsp; &nbsp; &nbsp; &nbsp; //&nbsp; &nbsp;{B1, B2}&nbsp; &nbsp; &nbsp; &nbsp; //&nbsp; &nbsp;{AA, BB}&nbsp; &nbsp; &nbsp; &nbsp; //&nbsp; &nbsp;{FF}&nbsp; &nbsp; &nbsp; &nbsp; //&nbsp; &nbsp;{ZZ}&nbsp; &nbsp; }}

jeck猫

正如另一位用户在评论中提到的那样,推出自己的解决方案并不简单。要解决此特定问题,您可以执行类似的操作&nbsp; &nbsp; String[] str = {"BB","2","1","3","AA","DD","A3","A1","EE","A2","4"};&nbsp; &nbsp; Map<String, List<String>> collect;&nbsp; &nbsp; collect = Arrays.stream(str)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .flatMap(s -> Stream.of(s.split("[^a-zA-Z0-9]")))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .filter(s -> !s.trim().isEmpty())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .sorted()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .collect(Collectors.groupingBy(s -> {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; final StringBuilder groupKey = new StringBuilder();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; char first = s.charAt(0);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (Character.isAlphabetic(first)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (first >= 'D') {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; groupKey.append("ALPHA-HIGH");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; groupKey.append("ALPHA-LOW");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; groupKey.append("NON-ALPHA");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (s.length() == 2) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; char second = s.charAt(1);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (Character.isAlphabetic(second)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (first >= 'D') {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; groupKey.append("_ALPHA-HIGH");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; groupKey.append("_ALPHA-LOW");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; groupKey.append("_NON-ALPHA");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return groupKey.toString();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }));这将为您提供所需的输出。请注意,使用键 (String) 而不是单个字符。这里发生了什么?您有很多不同的可能组,我将其视为两个宏组:字母组和非字母组。在你的情况下,非字母的东西是数字。长度为 2 的字符串可以将第二个字符作为字母或数字。如果 alpha 字符大于D或等于,则被认为是“高”。输出四组:NON-ALPHA: {1, 2, 3, 4}ALPHA-LOW_NON-ALPHA: {A1, A2, A3}ALPHA-HIGH_ALPHA-HIGH: {DD, EE}ALPHA-LOW_ALPHA-LOW: {AA, BB}

繁星coding

要构建这样的连续组,您首先需要定义一个函数,该函数采用两个项目来识别它们是否相互跟随,即按连续顺序排列。例如,“1”之后是“2”,但不是“3”或“A”;在您的示例中,“AA”后跟“BB”。有了这样的功能,您可以遍历排序列表并比较相邻的项目来决定是打开一个组、关闭它还是单独打印一个项目。我会调用这样的函数follows(String a, String b)。然后构建组的算法非常简单:static String printGroups(String[] items) {&nbsp; Arrays.sort(items);&nbsp; &nbsp; &nbsp; // strictly saying, sorting order must be consistent with `follows`&nbsp; boolean open = false;&nbsp; &nbsp; // a group is open currently&nbsp; StringBuilder result = new StringBuilder();&nbsp; for (int i = 0; i < items.length; ++i) {&nbsp; &nbsp; if (!open && i > 0) {&nbsp; &nbsp; &nbsp; result.append(',');&nbsp; &nbsp; }&nbsp; &nbsp; if (i < items.length - 1 && follows(items[i], items[i + 1])) {&nbsp; &nbsp; &nbsp; if (!open) {&nbsp; &nbsp; &nbsp; &nbsp; // open a group&nbsp; &nbsp; &nbsp; &nbsp; result.append('(').append(items[i]).append('-');&nbsp; &nbsp; &nbsp; &nbsp; open = true;&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; } else if (open) {&nbsp; &nbsp; &nbsp; // close the group&nbsp; &nbsp; &nbsp; result.append(items[i]).append(')');&nbsp; &nbsp; &nbsp; open = false;&nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; // print a standalone item&nbsp; &nbsp; &nbsp; result.append(items[i]);&nbsp; &nbsp; }&nbsp; }&nbsp; return result.toString();}该功能已根据您的示例进行了调整(看起来很糟糕,您可以使用 java 流或其他任何方式follows使其更清晰/可读)-StringUtilsstatic boolean follows(String a, String b) {&nbsp; &nbsp; if (a.length() != b.length() && a.length() == 0) {&nbsp; &nbsp; &nbsp; &nbsp; return false;&nbsp; &nbsp; }&nbsp; &nbsp; // AAA -> BBB&nbsp; &nbsp; if (allSame(a) && allSame(b) && (b.charAt(0) - a.charAt(0) == 1)) {&nbsp; &nbsp; &nbsp; &nbsp; return true;&nbsp; &nbsp; }&nbsp; &nbsp; // ABC1 -> ABC2&nbsp; &nbsp; // finding common prefix&nbsp; &nbsp; int p = 0;&nbsp; &nbsp; while (p < a.length() && a.charAt(p) == b.charAt(p)) {&nbsp; &nbsp; &nbsp; &nbsp; ++p;&nbsp; &nbsp; }&nbsp; &nbsp; return (p == a.length() - 1) && (b.charAt(p) - a.charAt(p) == 1);}static boolean allSame(String chars) {&nbsp; &nbsp; char s = chars.charAt(0);&nbsp; &nbsp; return chars.chars().allMatch(c -> s == c);}之后,您只需将文本拆分为项目并提要:printGroups("BB,2,1,3,AA,DD,A3,A1,EE,A2,4".split(","));&nbsp; // (1-4),(A1-A3),(AA-BB),(DD-EE)
随时随地看视频慕课网APP

相关分类

Java
我要回答