对包含数字的字符串数组进行排序
Sorting array of strings that contain number
我正在为我的大学实现一些代码,我必须按名称对两个 类 进行排序。因此,我开始对字符串使用 Java 的 compareTo
,但它没有正确执行。比如我有TEST-6
和TEST-10
这两个名字。但是,结果 TEST-10
领先于 TEST-6
。
我已经搜索并找到了这个解决方案:
private int compare(String o1, String o2) {
return extractInt(o1) - extractInt(o2);
}
private int extractInt(String s) {
String num = s.replaceAll("\D", "");
// return 0 if no digits found
return num.isEmpty() ? 0 : Integer.parseInt(num);
}
但我的字符串可以采用任何形式。当我尝试这个测试时:TEST-6
和 TEST10
) 结果是 TEST-6
领先于 TEST10
,但我期望的是 TEST10
然后是 TEST-6
.
预期的结果应该是正常的字符串比较,但在需要时比较完整的数字。因此,如果数字之前的子字符串相等,则比较数字,如果不相等,则继续比较字符串。
或者像这样:
TE
TES-100
TEST-1
TEST-6
TESTT-0
TEXT-2
109
你可以这样做:
list.sort(Comparator.comparing(YourClass::removeNumbers).thenComparing(YourClass::keepNumbers));
这是两种方法:
private static String removeNumbers(String s) {
return s.replaceAll("\d", "");
}
private static Integer keepNumbers(String s) {
String number = s.replaceAll("\D", "");
if (!number.isEmpty()) {
return Integer.parseInt(number);
}
return 0;
}
对于以下数据:
List<String> list = new ArrayList<>();
list.add("TEXT-2");
list.add("TEST-6");
list.add("TEST-1");
list.add("109");
list.add("TE");
list.add("TESTT-0");
list.add("TES-100");
这是排序结果:
[109, TE, TES-100, TEST-1, TEST-6, TESTT-0, TEXT-2]
这是我们用来对可以在任何位置包含多个数字的字符串进行排序的比较方法(例如 "TEST-10.5"
或 "TEST-42-Subsection-3"
之类的字符串):
boolean isDigit( char c ) {
return '0' <= c && c <= '9';
}
int compare( String left, String right, Collator collator ) {
if ( left == null || right == null ) {
return left == right ? 0 : ( left == null ? -1 : 1 );
}
String s1 = left.trim();
String s2 = right.trim();
int l1 = s1.length();
int l2 = s2.length();
int i1 = 0;
int i2 = 0;
while ( i1 < l1 && i2 < l2 ) {
boolean isSectionNumeric = isDigit( s1.charAt( i1 ) );
if ( isSectionNumeric != isDigit( s2.charAt( i2 ) ) ) {
// one of the strings now enters a digit section and one is in a text section so we're done
//switch to -1 : 1 if you want numbers before text
return isSectionNumeric ? 1 : -1;
}
// read next section
int start1 = i1;
int start2 = i2;
for ( ++i1; i1 < l1 && isDigit( s1.charAt( i1 ) ) == isSectionNumeric; ++i1 ){/* no operation */}
for ( ++i2; i2 < l2 && isDigit( s2.charAt( i2 ) ) == isSectionNumeric; ++i2 ){/* no operation */}
String section1 = s1.substring( start1, i1 );
String section2 = s2.substring( start2, i2 );
// compare the sections:
int result =
isSectionNumeric ? Long.valueOf( section1 ).compareTo( Long.valueOf( section2 ) )
: collator == null ? section1.trim().compareTo( section2.trim() )
: collator.compare( section1.trim(), section2.trim() );
if ( result != 0 ) {
return result;
}
if ( isSectionNumeric ) {
// skip whitespace
for (; i1 < l1 && Character.isWhitespace( s1.charAt( i1 ) ); ++i1 ){/* no operation */}
for (; i2 < l2 && Character.isWhitespace( s2.charAt( i2 ) ); ++i2 ){/* no operation */}
}
}
// we've reached the end of both strings but they still are equal, so let's do a "normal" comparison
if ( i1 == l1 && i2 == l2 ) {
return collator == null ? left.compareTo( right ) : collator.compare( left, right );
}
// we've reached the end of only one string, so the other must either be greater or smaller
return ( i1 == l1 )? -1 : 1;
}
思路是将字符串"split"分成"text"和数字部分,然后一一比较。将支持小数,因为整数、小数点和小数部分将是 3 个单独比较的部分。
这基本上类似于将字符串拆分为子字符串数组并比较每个对应索引处的元素。那么你有以下几种情况:
- 两个元素都是文本:进行正常的字符串比较
- 两个元素都代表数字:解析并比较数字
- 一个元素是文本,另一个代表数字:决定哪个更大
- 我们已经到达两个字符串的末尾,但所有元素都相等:我们可以完成或对整个字符串进行 "normal" 比较以获得可能的顺序
- 我们只到达了一个字符串的末尾,它们仍然相等:据报告越长的字符串越大(一定是因为内容更多;))
请注意,这只是我们的做法,还有其他方式(例如,不跳过空格的方式)。
如果我是对的,问题出在你的字符 '-' 上,通过使用 string.replace("-","") 然后你可以继续正常排序,将字符串作为它用于排序,希望它能如您所愿。
String num = s.replaceAll("\D", "").replace("-","");
如果你没有任何负值,它应该可以工作,即使这样应用正则表达式来检查它是负数还是包含“-”的字符串。
我正在为我的大学实现一些代码,我必须按名称对两个 类 进行排序。因此,我开始对字符串使用 Java 的 compareTo
,但它没有正确执行。比如我有TEST-6
和TEST-10
这两个名字。但是,结果 TEST-10
领先于 TEST-6
。
我已经搜索并找到了这个解决方案:
private int compare(String o1, String o2) {
return extractInt(o1) - extractInt(o2);
}
private int extractInt(String s) {
String num = s.replaceAll("\D", "");
// return 0 if no digits found
return num.isEmpty() ? 0 : Integer.parseInt(num);
}
但我的字符串可以采用任何形式。当我尝试这个测试时:TEST-6
和 TEST10
) 结果是 TEST-6
领先于 TEST10
,但我期望的是 TEST10
然后是 TEST-6
.
预期的结果应该是正常的字符串比较,但在需要时比较完整的数字。因此,如果数字之前的子字符串相等,则比较数字,如果不相等,则继续比较字符串。 或者像这样:
TE
TES-100
TEST-1
TEST-6
TESTT-0
TEXT-2
109
你可以这样做:
list.sort(Comparator.comparing(YourClass::removeNumbers).thenComparing(YourClass::keepNumbers));
这是两种方法:
private static String removeNumbers(String s) {
return s.replaceAll("\d", "");
}
private static Integer keepNumbers(String s) {
String number = s.replaceAll("\D", "");
if (!number.isEmpty()) {
return Integer.parseInt(number);
}
return 0;
}
对于以下数据:
List<String> list = new ArrayList<>();
list.add("TEXT-2");
list.add("TEST-6");
list.add("TEST-1");
list.add("109");
list.add("TE");
list.add("TESTT-0");
list.add("TES-100");
这是排序结果:
[109, TE, TES-100, TEST-1, TEST-6, TESTT-0, TEXT-2]
这是我们用来对可以在任何位置包含多个数字的字符串进行排序的比较方法(例如 "TEST-10.5"
或 "TEST-42-Subsection-3"
之类的字符串):
boolean isDigit( char c ) {
return '0' <= c && c <= '9';
}
int compare( String left, String right, Collator collator ) {
if ( left == null || right == null ) {
return left == right ? 0 : ( left == null ? -1 : 1 );
}
String s1 = left.trim();
String s2 = right.trim();
int l1 = s1.length();
int l2 = s2.length();
int i1 = 0;
int i2 = 0;
while ( i1 < l1 && i2 < l2 ) {
boolean isSectionNumeric = isDigit( s1.charAt( i1 ) );
if ( isSectionNumeric != isDigit( s2.charAt( i2 ) ) ) {
// one of the strings now enters a digit section and one is in a text section so we're done
//switch to -1 : 1 if you want numbers before text
return isSectionNumeric ? 1 : -1;
}
// read next section
int start1 = i1;
int start2 = i2;
for ( ++i1; i1 < l1 && isDigit( s1.charAt( i1 ) ) == isSectionNumeric; ++i1 ){/* no operation */}
for ( ++i2; i2 < l2 && isDigit( s2.charAt( i2 ) ) == isSectionNumeric; ++i2 ){/* no operation */}
String section1 = s1.substring( start1, i1 );
String section2 = s2.substring( start2, i2 );
// compare the sections:
int result =
isSectionNumeric ? Long.valueOf( section1 ).compareTo( Long.valueOf( section2 ) )
: collator == null ? section1.trim().compareTo( section2.trim() )
: collator.compare( section1.trim(), section2.trim() );
if ( result != 0 ) {
return result;
}
if ( isSectionNumeric ) {
// skip whitespace
for (; i1 < l1 && Character.isWhitespace( s1.charAt( i1 ) ); ++i1 ){/* no operation */}
for (; i2 < l2 && Character.isWhitespace( s2.charAt( i2 ) ); ++i2 ){/* no operation */}
}
}
// we've reached the end of both strings but they still are equal, so let's do a "normal" comparison
if ( i1 == l1 && i2 == l2 ) {
return collator == null ? left.compareTo( right ) : collator.compare( left, right );
}
// we've reached the end of only one string, so the other must either be greater or smaller
return ( i1 == l1 )? -1 : 1;
}
思路是将字符串"split"分成"text"和数字部分,然后一一比较。将支持小数,因为整数、小数点和小数部分将是 3 个单独比较的部分。
这基本上类似于将字符串拆分为子字符串数组并比较每个对应索引处的元素。那么你有以下几种情况:
- 两个元素都是文本:进行正常的字符串比较
- 两个元素都代表数字:解析并比较数字
- 一个元素是文本,另一个代表数字:决定哪个更大
- 我们已经到达两个字符串的末尾,但所有元素都相等:我们可以完成或对整个字符串进行 "normal" 比较以获得可能的顺序
- 我们只到达了一个字符串的末尾,它们仍然相等:据报告越长的字符串越大(一定是因为内容更多;))
请注意,这只是我们的做法,还有其他方式(例如,不跳过空格的方式)。
如果我是对的,问题出在你的字符 '-' 上,通过使用 string.replace("-","") 然后你可以继续正常排序,将字符串作为它用于排序,希望它能如您所愿。
String num = s.replaceAll("\D", "").replace("-","");
如果你没有任何负值,它应该可以工作,即使这样应用正则表达式来检查它是负数还是包含“-”的字符串。