如何创建自定义比较器来对编号系统进行排序
How to create a custom comparator to sort a numbering system
这是我目前的代码:
package Demo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class Demo {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("3.3.x");
list.add("1.2.x");
list.add("2.3.x");
VersionComparator x = new VersionComparator();
Collections.sort(list, x );
for(String str : list)
System.out.println(str);
}
static class VersionComparator implements Comparator {
public int compare(String str1, String str2) {
String firstNumberStringOne = str1.split(".")[0];
String firstNumberStringTwo = str2.split(".")[0];
String secondNumberStringOne = str1.split(".")[1];
String secondNumberStringTwo = str2.split(".")[1];
return;
}
@Override
public int compare(Object o1, Object o2) {
// TODO Auto-generated method stub
return 0;
}
}
}
我想按照出现在句点之前的第一个数字对列表中的项目进行排序。如果这两个数字相等,则转到第二个数字并比较这些数字。如果等于 return 他们。
我不知道如何使用比较器。我试图实现它,但编译器抱怨我需要在第二个比较方法中添加覆盖。我也不知道如何根据 returned 的方式进行比较。我知道如果它等于那么它 return 是 0 小于它 return 是 -1 并且大于 1。但是在编码方面我不知道程序是如何知道的如何排序。
您的 VersionComparator
class 正在实现 Comparator
接口的原始形式,其中 compare
方法将占用 2 Object
秒而不是 2 String
s.
通过提供 String
作为类型参数来实现接口。然后编译器将识别您的 compare
方法,将 String
作为参数作为接口的正确实现。您不需要 compare
方法占用 Object
秒。
static class VersionComparator implements Comparator<String> {
您当然需要在 compare
method 中实现比较逻辑,如果 str1
比较小于,则返回 int
小于 0、0 或大于 0,根据您的自定义排序顺序等于或大于 str2
。
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("3.3.x");
list.add("1.2.x");
list.add("1.11.x");
list.add("1.1.x");
list.add("2.3.x");
Collections.sort(list, new VersionComparator());
for(String str : list)
System.out.println(str);
}
static class VersionComparator implements Comparator<String> {
//Temporary Cache Map to hold Split String value. String as Key and Split String array as value is this in this map.
Map<String, String[]> mCacheMap = new HashMap<>();
@Override
public int compare(String string1, String string2) {
if(!mCacheMap.containsKey(string1)){
//Put Split String of string1 to map if it does not contain it.
mCacheMap.put(string1, string1.split("\."));
}
if(!mCacheMap.containsKey(string2)){
//Put Split String of string2 to map if it does not contain it.
mCacheMap.put(string2, string2.split("\."));
}
//Get First Digit of first string1 from Map
Integer string1Val1 = Integer.valueOf(mCacheMap.get(string1)[0]);
//Get First Digit of second string2 from Map
Integer string2Val1 = Integer.valueOf(mCacheMap.get(string2)[0]);
//Compare Both Digit. compareTo Method return a negative integer, zero, or a positive integer as first Integer value is less than, equal to, or greater than the seconf Integer value.
int cmp = string1Val1.compareTo(string2Val1);
if( cmp != 0 ){
return cmp;
}else {
//If First digit of both string is same compare second digit.
Integer string1Val2 = Integer.valueOf(mCacheMap.get(string1)[1]);
Integer string2Val2 = Integer.valueOf(mCacheMap.get(string2)[1]);
return string1Val2.compareTo(string2Val2);
}
}
}
结果:
1.1.x
1.2.x
1.11.x
2.3.x
3.3.x
您的代码几乎没有问题:
您正在使用原始类型比较器
class VersionComparator implements Comparator // no <Type> here
因此 Comparator<T>
的编译器将尝试将 Object
用作 T
。这意味着它会将 compare(T t1, T t2)
方法编译为 compare(Object t1, Object t2)
。
如果您希望该方法编译为 compare(String t1, String o2)
,那么
- 它只接受
String
个参数
- 它可以在内部使用像
length()
这样的字符串方法
通过
将<String>
设置为通用类型
class VersionComparator implements Comparator<String>
现在编译器会知道 T
是 String
。
当您调用 split(".")
时,您不是在点上拆分,而是在 任何字符 上拆分(行分隔符除外),因为 split
使用正则表达式 (regex),在正则表达式中 .
表示行分隔符旁边的任何字符。因此,在开始时您将获得空元素数组,这些元素随后将被清除,因为 split(regex)
删除了空尾随字符串。更多信息在这里:.
要解决此问题,您需要使用 "\."
.
转义 .
这应该涵盖您代码中的主要问题。但是,如果您想创建不错的解决方案,请考虑避免排序 Strings
而是您自己的实例 Version
class.
这种方法的优点是,您不必每次比较两个字符串时都将 String 解析为 int(这可能代价高昂),但您可以将 "1.2.3"
的解析版本存储为数组 [1, 2, 3]
并在需要时重复使用。
Version
class 也可以实现 Comparable<Vector>
来提供默认的比较方法。
因此您的代码看起来更像:
class Version implements Comparable<Version> {
private String versionStr;
private int[] arr;
public String getVersionStr() { return versionStr; }
@Override public String toString() { return versionStr; }
@Override
public int compareTo(Version other) {
int result = Integer.compare(arr[0], other.arr[0]);
if (result != other)
return result;
return Integer.compare(arr[1], other.arr[1]);
}
public Version(String versionStr) {
this.versionStr = versionStr;
this.arr = Stream.of(versionStr.split("\."))
.limit(2)//get only two first elements
.mapToInt(Integer::parseInt)//convert String to int
.toArray();//create array with integers
}
}
class Demo {
public static void main(String[] args) {
List<Version> list = new ArrayList<Version>();
list.add(new Version("3.3.x"));
list.add(new Version("1.2.x"));
list.add(new Version("1.11.x"));
list.add(new Version("2.3.x"));
Collections.sort(list);//with use default order provided by compareTo(Version other)
for (Version str : list)
System.out.println(str);
}
}
这是我目前的代码:
package Demo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class Demo {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("3.3.x");
list.add("1.2.x");
list.add("2.3.x");
VersionComparator x = new VersionComparator();
Collections.sort(list, x );
for(String str : list)
System.out.println(str);
}
static class VersionComparator implements Comparator {
public int compare(String str1, String str2) {
String firstNumberStringOne = str1.split(".")[0];
String firstNumberStringTwo = str2.split(".")[0];
String secondNumberStringOne = str1.split(".")[1];
String secondNumberStringTwo = str2.split(".")[1];
return;
}
@Override
public int compare(Object o1, Object o2) {
// TODO Auto-generated method stub
return 0;
}
}
}
我想按照出现在句点之前的第一个数字对列表中的项目进行排序。如果这两个数字相等,则转到第二个数字并比较这些数字。如果等于 return 他们。
我不知道如何使用比较器。我试图实现它,但编译器抱怨我需要在第二个比较方法中添加覆盖。我也不知道如何根据 returned 的方式进行比较。我知道如果它等于那么它 return 是 0 小于它 return 是 -1 并且大于 1。但是在编码方面我不知道程序是如何知道的如何排序。
您的 VersionComparator
class 正在实现 Comparator
接口的原始形式,其中 compare
方法将占用 2 Object
秒而不是 2 String
s.
通过提供 String
作为类型参数来实现接口。然后编译器将识别您的 compare
方法,将 String
作为参数作为接口的正确实现。您不需要 compare
方法占用 Object
秒。
static class VersionComparator implements Comparator<String> {
您当然需要在 compare
method 中实现比较逻辑,如果 str1
比较小于,则返回 int
小于 0、0 或大于 0,根据您的自定义排序顺序等于或大于 str2
。
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("3.3.x");
list.add("1.2.x");
list.add("1.11.x");
list.add("1.1.x");
list.add("2.3.x");
Collections.sort(list, new VersionComparator());
for(String str : list)
System.out.println(str);
}
static class VersionComparator implements Comparator<String> {
//Temporary Cache Map to hold Split String value. String as Key and Split String array as value is this in this map.
Map<String, String[]> mCacheMap = new HashMap<>();
@Override
public int compare(String string1, String string2) {
if(!mCacheMap.containsKey(string1)){
//Put Split String of string1 to map if it does not contain it.
mCacheMap.put(string1, string1.split("\."));
}
if(!mCacheMap.containsKey(string2)){
//Put Split String of string2 to map if it does not contain it.
mCacheMap.put(string2, string2.split("\."));
}
//Get First Digit of first string1 from Map
Integer string1Val1 = Integer.valueOf(mCacheMap.get(string1)[0]);
//Get First Digit of second string2 from Map
Integer string2Val1 = Integer.valueOf(mCacheMap.get(string2)[0]);
//Compare Both Digit. compareTo Method return a negative integer, zero, or a positive integer as first Integer value is less than, equal to, or greater than the seconf Integer value.
int cmp = string1Val1.compareTo(string2Val1);
if( cmp != 0 ){
return cmp;
}else {
//If First digit of both string is same compare second digit.
Integer string1Val2 = Integer.valueOf(mCacheMap.get(string1)[1]);
Integer string2Val2 = Integer.valueOf(mCacheMap.get(string2)[1]);
return string1Val2.compareTo(string2Val2);
}
}
}
结果:
1.1.x
1.2.x
1.11.x
2.3.x
3.3.x
您的代码几乎没有问题:
您正在使用原始类型比较器
class VersionComparator implements Comparator // no <Type> here
因此
Comparator<T>
的编译器将尝试将Object
用作T
。这意味着它会将compare(T t1, T t2)
方法编译为compare(Object t1, Object t2)
。如果您希望该方法编译为
compare(String t1, String o2)
,那么- 它只接受
String
个参数 - 它可以在内部使用像
length()
这样的字符串方法
通过
将<String>
设置为通用类型class VersionComparator implements Comparator<String>
现在编译器会知道
T
是String
。- 它只接受
当您调用
split(".")
时,您不是在点上拆分,而是在 任何字符 上拆分(行分隔符除外),因为split
使用正则表达式 (regex),在正则表达式中.
表示行分隔符旁边的任何字符。因此,在开始时您将获得空元素数组,这些元素随后将被清除,因为split(regex)
删除了空尾随字符串。更多信息在这里:.要解决此问题,您需要使用
"\."
. 转义
.
这应该涵盖您代码中的主要问题。但是,如果您想创建不错的解决方案,请考虑避免排序 Strings
而是您自己的实例 Version
class.
这种方法的优点是,您不必每次比较两个字符串时都将 String 解析为 int(这可能代价高昂),但您可以将 "1.2.3"
的解析版本存储为数组 [1, 2, 3]
并在需要时重复使用。
Version
class 也可以实现 Comparable<Vector>
来提供默认的比较方法。
因此您的代码看起来更像:
class Version implements Comparable<Version> {
private String versionStr;
private int[] arr;
public String getVersionStr() { return versionStr; }
@Override public String toString() { return versionStr; }
@Override
public int compareTo(Version other) {
int result = Integer.compare(arr[0], other.arr[0]);
if (result != other)
return result;
return Integer.compare(arr[1], other.arr[1]);
}
public Version(String versionStr) {
this.versionStr = versionStr;
this.arr = Stream.of(versionStr.split("\."))
.limit(2)//get only two first elements
.mapToInt(Integer::parseInt)//convert String to int
.toArray();//create array with integers
}
}
class Demo {
public static void main(String[] args) {
List<Version> list = new ArrayList<Version>();
list.add(new Version("3.3.x"));
list.add(new Version("1.2.x"));
list.add(new Version("1.11.x"));
list.add(new Version("2.3.x"));
Collections.sort(list);//with use default order provided by compareTo(Version other)
for (Version str : list)
System.out.println(str);
}
}