3 回答

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

TA貢獻1909條經驗 獲得超7個贊
正如另一位用戶在評論中提到的那樣,推出自己的解決方案并不簡單。要解決此特定問題,您可以執(zhí)行類似的操作
String[] str = {"BB","2","1","3","AA","DD","A3","A1","EE","A2","4"};
Map<String, 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 -> {
final StringBuilder groupKey = new StringBuilder();
char first = s.charAt(0);
if (Character.isAlphabetic(first)) {
if (first >= 'D') {
groupKey.append("ALPHA-HIGH");
} else {
groupKey.append("ALPHA-LOW");
}
} else {
groupKey.append("NON-ALPHA");
}
if (s.length() == 2) {
char second = s.charAt(1);
if (Character.isAlphabetic(second)) {
if (first >= 'D') {
groupKey.append("_ALPHA-HIGH");
} else {
groupKey.append("_ALPHA-LOW");
}
} else {
groupKey.append("_NON-ALPHA");
}
}
return groupKey.toString();
}));
這將為您提供所需的輸出。請注意,使用鍵 (String) 而不是單個字符。
這里發(fā)生了什么?您有很多不同的可能組,我將其視為兩個宏組:字母組和非字母組。在你的情況下,非字母的東西是數(shù)字。長度為 2 的字符串可以將第二個字符作為字母或數(shù)字。如果 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}

TA貢獻1797條經驗 獲得超4個贊
要構建這樣的連續(xù)組,您首先需要定義一個函數(shù),該函數(shù)采用兩個項目來識別它們是否相互跟隨,即按連續(xù)順序排列。例如,“1”之后是“2”,但不是“3”或“A”;在您的示例中,“AA”后跟“BB”。有了這樣的功能,您可以遍歷排序列表并比較相鄰的項目來決定是打開一個組、關閉它還是單獨打印一個項目。
我會調用這樣的函數(shù)follows(String a, String b)。然后構建組的算法非常簡單:
static String printGroups(String[] items) {
Arrays.sort(items); // strictly saying, sorting order must be consistent with `follows`
boolean open = false; // a group is open currently
StringBuilder result = new StringBuilder();
for (int i = 0; i < items.length; ++i) {
if (!open && i > 0) {
result.append(',');
}
if (i < items.length - 1 && follows(items[i], items[i + 1])) {
if (!open) {
// open a group
result.append('(').append(items[i]).append('-');
open = true;
}
} else if (open) {
// close the group
result.append(items[i]).append(')');
open = false;
} else {
// print a standalone item
result.append(items[i]);
}
}
return result.toString();
}
該功能已根據(jù)您的示例進行了調整(看起來很糟糕,您可以使用 java 流或其他任何方式follows使其更清晰/可讀)-StringUtils
static boolean follows(String a, String b) {
if (a.length() != b.length() && a.length() == 0) {
return false;
}
// AAA -> BBB
if (allSame(a) && allSame(b) && (b.charAt(0) - a.charAt(0) == 1)) {
return true;
}
// ABC1 -> ABC2
// finding common prefix
int p = 0;
while (p < a.length() && a.charAt(p) == b.charAt(p)) {
++p;
}
return (p == a.length() - 1) && (b.charAt(p) - a.charAt(p) == 1);
}
static boolean allSame(String chars) {
char s = chars.charAt(0);
return chars.chars().allMatch(c -> s == c);
}
之后,您只需將文本拆分為項目并提要:
printGroups("BB,2,1,3,AA,DD,A3,A1,EE,A2,4".split(",")); // (1-4),(A1-A3),(AA-BB),(DD-EE)
添加回答
舉報