This question already has answers here:
How are Anonymous inner classes used in Java?
(18 answers)
Closed 7 years ago.
Recently I'm trying to get more familiar with the Comparator interface in Java. I have an exercise which is about to sort the ArrayList of strings from the shortest to longest. I used a Comparator of Strings. When searching the net, I found the following solution proposal:
public static Comparator<String> lengthComparator = new Comparator<String>() {
#Override
public int compare(String a, String b) {
if (a.length() == b.length()) {
return a.compareTo(b);
} else {
return (a.length() > b.length() ? 1 : -1);
}
}
};
Then I used it in my code to sort the set:
Collections.sort(set, lengthComparator);
And it worked. What I'd like to ask is the specific way of defining the lengthComparator object here. We create a new object:
new Comparator<String>()
with the default constructor. But then there is a further code with overwritten method in "{}" brackets. Is it a normal way of creating objects? I've never met it before and I'd like to learn more about it. Could you please advise me some referal materials where I can find more informations about it?
Yes this is a common way to create objects, it is called anonymous class.
Comparator is an interface, and you want a class to be instantiated, so you create an object from an anonymous class that implements Comparator.
Anonymous class example
public void sortSetByStringLength(Set set) {
Comparator<String> lengthComparator = new Comparator<String>() {
#Override
public int compare(String a, String b) {
if (a.length() == b.length()) {
return a.compareTo(b);
} else {
return (a.length() > b.length() ? 1 : -1);
}
}
}
Collections.sort(set, lengthComparator);
}
Regular class example
public class LengthComparator implements Comparator<String> {
#Override
public int compare(String a, String b) {
if (a.length() == b.length()) {
return a.compareTo(b);
} else {
return (a.length() > b.length() ? 1 : -1);
}
}
}
And in your program sort a list this way :
public void sortSetByStringLength(Set set) {
Collections.sort(set, new LengthComparator());
}
I'm not sure what's the exact question but as it was already said :
What you have instanciated is an anonymous class. Indeed, as you already know an interface cannot be instanciated.
So, when you do :
new Comparator<String>()
{
#Override
public int compare(String o1, String o2) {
// TODO Auto-generated method stub
return 0;
}
});
it is like you've created a class called let's say : LengthComparator like this :
public class LengthComparator implements Comparator<String>{
public LengthComparator()
{
}
#Override
public int compare(String o1, String o2) {
int ack = 0;
if(o1 == null && o2 == null){
ack = 0;
}
else if(o1 != null && o2 == null){
// Decide what you should do here !
// returnValue = ???
}
else if(o1 == null && o2 != null){
// Decide here, too !
// returnValue = ???
}
else{
if(o1.length() == o2.length()){
// Sort by order ...
ack = o1.compareTo(o2);
}
else{
ack = o1.length() > o2.length() ? 1 : -1;
}
}
return ack;
}
}
As a personal advice, always check your arguments toward null values as you don't really know what is going to be passed in...
I want to sort a list of String that also contains numbers.
For example, I have a list containing elements "1,2,3,4,5,11,12,21,22,31,32,A101,A102,A103,A104,B405".
If i use Collection.sort method means output is "1,11,12,2,21,22,3,31,32... ".
If i use Comparator function means it gives
output as "1,2,3,4,5,11,12,21,22,31,32,A101... ".
But i need to display as
"A101,A102,A103,A104,B405,1,2,3,4,5,11,12,21,22,31,32"
Please any one give me a solution. Thanks in advance.
Implement your own comparator that tries to convert the objects to be compared to an integer, and if succesful, uses the compareTo of the Integer class, and otherwise uses the compareTo of the String class.
Like this:
public class MyComparator implements Comparator<String,String>
{
public int compare(String s1, String s2)
{
try
{
int i1 = Integer.parseInt(s1);
int i2 = Integer.parseInt(s2);
return i1 - i2;
}
catch (NumberFormatException e)
{
return s1.compareTo(s2);
}
}
}
ArrayList<String> myList = (...);
Collections.sort(myList,new MyComparator());
As commented, this sorts like this 1,12,A102,A103. But wanted is: A102,A103,1,12. To do this we need to take care of situations where s1 is parsable as int and s2 is not and the other way around. I'm not sure if I got -1 and 1 right, so maybe they should be swapped.
public class MyComparator implements Comparator<String,String>
{
public int compare(String s1, String s2)
{
Integer i1 = null
Integer i2 = null
try
{
i1 = Integer.parseInt(s1);
}
catch (NumberFormatException e) {}
try
{
i2 = Integer.parseInt(s2);
}
catch (NumberFormatException e) {}
if (i1 == null && i2 == null)
return s1.compareTo(s2);
if (i1 == null && i2 != null)
return -1;
if (i1 != null && i2 == null)
return 1;
return i1 - i2;
}
}
Create a new "holder" object for the strings and implement the Comparable interface. Override the "compareTo" method. That should do the trick ;)
Answer is present there in your question, just create two lists and sort them separately!
package com.kvvssut.misc;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class SortStringThenNumber {
public static void main(String[] args) {
List<String> inputs = Arrays.asList(new String[]{"1","5","3","4","2","11","11","21","31","32","22","A101","A103","A104","B405","A102"});
List<Object> result = sortStringThenNumber(inputs);
for (Object sorted : result) {
System.out.println(String.valueOf(sorted));
}
}
private static List<Object> sortStringThenNumber(List<String> inputs) {
List<Integer> numbers = new ArrayList<Integer>();
List<String> strings = new ArrayList<String>();
for (String input : inputs) {
if (input.matches("-?\\d+")) {
numbers.add(Integer.valueOf(input));
} else {
strings.add(input);
}
}
inputs = null;
Collections.sort(numbers);
Collections.sort(strings);
ArrayList<Object> all = new ArrayList<Object>();
all.addAll(strings);
all.addAll(numbers);
return all;
}
}
How to add String[] into Set avoiding exception.
I put array's size to 100, it doesn't need to be fixed size array but
I need to have access to array's members like x[] so i can insert array values.
Set<String[]> s = new TreeSet<String[]>();
String[] x = new String[100];
int i=0;
x[i++] = ...
x[i++] = ...
s.add(x);
Ljava.lang.String; cannot be cast to java.lang.Comparable
at java.util.TreeMap.compare(TreeMap.java:1188)
at java.util.TreeMap.put(TreeMap.java:531)
at java.util.TreeSet.add(TreeSet.java:255)
Arrays don't have a "natural order", that's why you got this exception.
One way is to provide a custom comparator when constructing your TreeSet.
Set<String[]> s = new TreeSet<String[]>(new Comparator<String[]>() {
#Override
public int compare(String[] o1, String[] o2) {
//your logic here
}
});
But I don't think you should use a TreeSet for that sort of things because that will be hard to tell how to define an order for comparing your arrays.
IMO your best option is to create a wrapper class, overriding hashcode and equals and put those in an HashSet.
class WrapperStringArray {
private String[] arr;
//constructors, getters, setter and additional methods
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(arr);
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
WrapperStringArray other = (WrapperStringArray) obj;
return Arrays.equals(arr, other.arr);
}
}
Hi I need any method or explanation on how we can order multiple column values in java.
The output should be similar to the multiple column order output in MySQL.
for clarification please check the below link
http://www.dynamicdrive.com/forums/showthread.php?19797-ORDER-BY-Multiple-Columns
Let's say your object looks like this:
public DataObject {
public String name;
public int age;
public String hairColour;
}
Let's say you want to sort them based on age, then hair colour, then name. You could create a comparator as follows:
public DataObjectComparator extends Comparator<DataObject> {
public int compare(DataObject o1, DataObject o2) {
// if the age is the same
if(o1.age == o2.age) {
// if the hair colour is the same
if(o1.hairColour.compareTo(o2.hairColour) == 0) {
// return the name comparison
return o1.name.compareTo(o2.name);
} else { // else return the hair colour comparison
return o1.hairColour.compareTo(o2.hairColour);
}
} else { // else return the age comparison
return o1 < o2 ? -1 : 1;
}
}
}
You can sort arraylist for multiple properties using below sample comparator.
public class CustomeClass implements Comparator<CustomeObject> {
public int compare(CustomeObject o1, CustomeObject o2) {
int value1 = o1.prop1.compareTo(o2.prop1);
if (value1 == 0) {
int value2 = o1.prop2.compareTo(o2.prop2);
if (value2 == 0) {
return o1.prop3.compareTo(o2.prop3);
} else {
return value2;
}
return value1;
}
}
Basically it continues comparing each successive attribute of your class whenever the compared attributes so far are equal (== 0).
I'm trying to sort an arraylist but I can't wrap my head around the comparator. I don't understand how to define sortable fields from my arraylist which is created from a text file. Furthermore I'm unsure of the comparator logic. It seems to me like create a set of comparator functions, and then later invoke them. Is this true?
So far my code looks like this:
public class coord implements Comparator<Sort> {
private int index;
private int index2;
private double dista;
}
public class Sort {
List<Sort> coords = new ArrayList<Sort>();
public static void main(String[] args) throws Exception {
ArrayList dist = new ArrayList();
File file = new File("2.txt");
FileWriter writer = new FileWriter("2c.txt");
try {
Scanner scanner = new Scanner(file).useDelimiter("\\s+");
while (scanner.hasNextLine())
{
int index = scanner.nextInt();
int index2 = scanner.nextInt();
double dista = scanner.nextDouble();
System.out.println(index + " " + index2 + " " + dista);
}
}
}
public class EmpSort {
static final Comparator<coord> SENIORITY_ORDER =
new Comparator<coord>() {
public int compare(coord e1, coord e2) {
return e2.index().compareTo(e1.index());
}
};
static final Collection<coord> coords = ;
public static void main(String[] args) {
List<Sorted>e = new ArrayList<Sorted>(coords);
Collections.sort(e, SENIORITY_ORDER);
System.out.println(e);
I appreciate any help anyone can give.
Comparator logic is simple. When you sort an array of elements you have two choices - sort using the Comparable on each element (assuming there is one) or supply a Comparator. If your array contains complex elements or there are different sort criteria then the latter choice is probably what you need to use.
Each time the comparator is called you must say if element 1 is "less than" element 2 in which case return a negative number, element 1 is "greater than" element 3 in which case return a positive number. Otherwise if elements are equal return 0. You may also do reference and null comparison before comparing values so that null elements are logically "less than" non-null elements and so on.
If elements are "equal" then you may wish to sort by a secondary field and then a third field and keep going until the sort order is unambiguous.
A simple comparator for a class Complex which has fields a & b and we want to sort on a:
class Complex {
public String a = "";
public String b = "";
}
//...
Collections.sort(someList, new Comparator<Complex>() {
public int compare(Complex e1, Complex e2) {
if (e1 == e2) {
// Refs could be null or equal
return 0;
}
if (e1 == null && e2 != null) {
return -1;
}
if (e2 == null && e1 != null) {
return 1;
}
if (e1.a == e2.a) {
return 0;
}
if (e1.a == null && e2.a != null) {
return -1;
}
if (e1.a != null && e2.a == null) {
return 1;
}
// Just use the Comparable on the fields
return e1.a.compareTo(e2.a);
}
});