Reputation: 15
Here is the code I have so far:
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;
}
}
}
I would like to sort the items in my list by the first number that appears before the period. If those two numbers are equal then go to the second number and compare those numbers. And if equal just return them.
I am not sure how to use the comparator. I tried to implement it and the compiler complained that I needed to add in the second compare method with the override. I also do not know how to do the comparison in terms of how it is being returned. I understand that if its equal then it returns a 0 and its less than then it returns a -1 and greater than a 1. But in terms of coding I am lost as to how does the program know how to sort it.
Upvotes: 1
Views: 6261
Reputation: 124215
There are few problems with your code:
You are using raw type Comparator
class VersionComparator implements Comparator // no <Type> here
so compiler for Comparator<T>
will try to use Object
as T
. This means that it will be compiling compare(T t1, T t2)
method as compare(Object t1, Object t2)
.
If you want that method to compile as compare(String t1, String o2)
so
String
arguments length()
set <String>
as generic type via
class VersionComparator implements Comparator<String>
Now compiler will know that T
is String
.
When you are calling split(".")
you are not splitting on dot, but on any character (except line separators) because split
is using regular expression (regex), and in regex .
represents any character beside line separators. Because of this at start you will get array of empty elements, which will then be cleared because split(regex)
removes empty trailing strings. More info here: https://stackoverflow.com/a/21790319/1393766.
To solve this problem you will need to escape .
for instance with "\\."
.
This should cover main problems in your code. But if you would like to create nice solution then consider avoiding sorting Strings
but rather instances of your own Version
class.
Advantage of this approach is that you will not have to parse your String to int each time you want to compare two strings (which can be costly), but you will be able to store parsed version of "1.2.3"
as array [1, 2, 3]
and reuse it when needed.
Also Version
class can implement Comparable<Vector>
to provide default comparing method.
So your code can look more like:
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);
}
}
Upvotes: 1
Reputation: 10299
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);
}
}
}
Results:
1.1.x
1.2.x
1.11.x
2.3.x
3.3.x
Upvotes: 0
Reputation: 178253
Your VersionComparator
class is implementing the raw form of the Comparator
interface, where the compare
method will take 2 Object
s instead of 2 String
s.
Implement the interface by supplying String
as a type parameter. Then the compiler will recognize your compare
method taking String
s as parameters as the proper implementation of the interface. You don't need a compare
method taking Object
s.
static class VersionComparator implements Comparator<String> {
You will of course need to implement the comparison logic in your compare
method, returning an int
less than 0, 0, or greater than 0 if str1
compares less than, equal to, or greater then str2
according to your custom sort order.
Upvotes: 2