Comparator interface - java

ok I was going to edit my previous question but i wasnt sure if it was the right way to do it so i'll just give another question about Comparator, now i want to be able to sort with different ways. I have a bank checks and i want to sort with checkNumber then checkAmount
i managed to do it with checkNumber but couldnt figure out how with checkAmount
here is how i did it for checkNumber:
import java.util.Comparator;
public class Check implements Comparator {
private int checkNumber;
private String description;
private double checkAmount;
public Check() {
}
public Check(int newCheckNumber, double newAmountNumber) {
setCheckNumber(newCheckNumber);
setAmountNumber(newAmountNumber);
}
public String toString() {
return checkNumber + "\t\t" + checkAmount;
}
public void setCheckNumber(int checkNumber) {
this.checkNumber = checkNumber;
}
public int getCheckNumber() {
return checkNumber;
}
public void setAmountNumber(double amountNumber) {
this.checkAmount = amountNumber;
}
public double getAmountNumber() {
return checkAmount;
}
#Override
public int compare(Object obj1, Object obj2) {
int value1 = ((Check) obj1).getCheckNumber();
int value2 = ((Check) obj2).getCheckNumber();
int result = 0;
if (value1 > value2){
result = 1;
}
else if(value1 < value2){
result = -1;
}
return result;
}
}
import java.util.ArrayList;
import java.util.Collections;
import test.CheckValue;
public class TestCheck {
public static void main(String[] args) {
ArrayList List = new ArrayList();
List.add(new Check(445, 55.0));
List.add(new Check(101,43.12));
List.add(new Check(110,101.0));
List.add(new Check(553,300.21));
List.add(new Check(123,32.1));
Collections.sort(List, new Check());
System.out.println("Check Number - Check Amount");
for (int i = 0; i < List.size(); i++){
System.out.println(List.get(i));
}
}
}
thank you very much in advance and please tell me if im submiting things in the wrong way.

What you really want to do is define a separate class to act as the Comparator object - don't make your actual Check class the comparator, but instead have 3 classes:
the Check class itself
a CheckAmountComparator class (or something similar) that implements Comparator<Check>
a CheckNumberComparator class (or something similar) that implements Comparator<Check>
Then when you want to sort one way or another, you simply pass an instance of the Comparator-implementing class corresponding to the type of sorting you want to do. For instance, to sort by amount, it'd then become...
Collections.sort(yourListVariable, new CheckAmountComparator());
Also - I'd highly suggest naming your variable something other than List, since List is used as a type name in Java.

You should make Check implements Comparable<Check>, but not itself implements Comparator.
A Comparable type defines the natural ordering for the type, and a Comparator for a type is usually not the type itself, and defines their own custom ordering of that type.
Related questions
When to use Comparable vs Comparator
Java: What is the difference between implementing Comparable and Comparator?
Can I use a Comparator without implementing Comparable?
Also, you shouldn't use raw type. You need to use parameterized generic types, Comparable<Check>, Comparator<Check>, List<Check>, etc.
Related questions
What is a raw type and why shouldn’t we use it?
A String example
Let's take a look at what String has:
public final class String implements Comparable<String>
String defines its natural ordering as case-sensitive
It has a field
public static final Comparator<String> CASE_INSENSITIVE_ORDER
Here we have a case-insensitive custom Comparator<String>
An example of using this is the following:
List<String> list = new ArrayList<String>(
Arrays.asList("A", "B", "C", "aa", "bb", "cc")
);
Collections.sort(list);
System.out.println(list);
// prints "[A, B, C, aa, bb, cc]"
Collections.sort(list, String.CASE_INSENSITIVE_ORDER);
System.out.println(list);
// prints "[A, aa, B, bb, C, cc]"
Here's an example of sorting List<String> using both its natural ordering and your own custom Comparator<String>. Note that we've defined our own Comparator<String> without even changing the final class String itself.
List<String> list = new ArrayList<String>(
Arrays.asList("1", "000000", "22", "100")
);
Collections.sort(list);
System.out.println(list);
// prints "[000000, 1, 100, 22]" natural lexicographical ordering
Comparator<String> lengthComparator = new Comparator<String>() {
#Override public int compare(String s1, String s2) {
return Integer.valueOf(s1.length())
.compareTo(s2.length());
}
};
Collections.sort(list, lengthComparator);
System.out.println(list);
// prints "[1, 22, 100, 000000]" ordered by length
Comparator<String> integerParseComparator = new Comparator<String>() {
#Override public int compare(String s1, String s2) {
return Integer.valueOf(Integer.parseInt(s1))
.compareTo(Integer.parseInt(s2));
}
};
Collections.sort(list, integerParseComparator);
System.out.println(list);
// prints "[000000, 1, 22, 100]" ordered by their values as integers
Conclusion
You can follow the example set by String, and do something like this:
public class Check implements Comparable<Check> {
public static final Comparator<Check> NUMBER_ORDER = ...
public static final Comparator<Check> AMOUNT_ORDER = ...
public static final Comparator<Check> SOMETHING_ELSE_ORDER = ...
}
Then you can sort a List<Check> as follows:
List<Check> checks = ...;
Collections.sort(checks, Check.AMOUNT_ORDER);

Related

sort values in linked list

I have values in linked list as
TY12354d,sfasdf,asfasf,2.35123412E8
TY12354dsaf,asdffasd,asfasfafsd,12344.0
Pranish,pranishfilan,viper,1234
zxs,asdf,asfd,1234
uv,vr,va,1234
www,dsf,ASDF,123
dsfgsdf,sd,sd,235
The values are seperated by commas which contains certain data. The first ones i.e TY12354d, TY12345saf, Pranish etc are the id, second i.e sfasdf, asdffasd, pranishfilan, etc are name.The values are viewed in jtextfield. I want to enable user to sort the datas according to the id when he clicks on "sort by id" button, name when he clicks on "sort by name" button and so on.
Try this one to sort by id.
LinkedList<String> list = new LinkedList<String>();
list.add("TY12354d,sfasdf,asfasf,2.35123412E8");
list.add("TY12354dsaf,asdffasd,asfasfafsd,12344.0");
list.add("Pranish,pranishfilan,viper,1234");
list.add("zxs,asdf,asfd,1234");
list.add("uv,vr,va,1234");
list.add("www,dsf,ASDF,123");
list.add("dsfgsdf,sd,sd,235");
Collections.sort(list, new Comparator<String>() {
public int compare(String a, String b) {
System.out.println(a+" --> "+b);
return a.substring(0, a.indexOf(',')).compareTo(b.substring(0, b.indexOf(',')));
}
});
Use same concept for name also.
output:
Pranish,pranishfilan,viper,1234
TY12354d,sfasdf,asfasf,2.35123412E8
TY12354dsaf,asdffasd,asfasfafsd,12344.0
dsfgsdf,sd,sd,235
uv,vr,va,1234
www,dsf,ASDF,123
zxs,asdf,asfd,1234
--EDIT--
as per OP last comment to compare on Car object
class Car {
String id;
String name;
public Car(String id, String name) {
this.id = id;
this.name = name;
}
// getter & setter
}
LinkedList<Car> list = new LinkedList<Car>();
list.add(new Car("TY12354d", "sfasdf"));
list.add(new Car("TY12354dsaf", "asdffasd"));
list.add(new Car("Pranish", "pranishfilan"));
list.add(new Car("zxs", "asdf"));
list.add(new Car("uv", "vr"));
list.add(new Car("www", "dsf"));
list.add(new Car("dsfgsdf", "sd"));
Collections.sort(list, new Comparator<Car>() {
public int compare(Car c1, Car c2) {
return c1.id.compareTo(c2.id);
}
});
You'll have to write your own comparator, or rewrite the structure. With a comparator you can simply use Collections.sort to sort the list.
There are many threads on implementing comparators here on stackoverflow, like this one. It's actually fairly simple.
It's not very efficient to sort a linked list, so if you don't use Collections.sort, which uses an intermediate array to sort, I'd suggest that you change your datastructure to e.g. an array or ArrayList. Or, even better: create a Class to represent your data and define comparators for that class.
Here's an example of a Comparator:
import java.util.*;
class Test {
static class IDComparator implements Comparator<String> {
#Override
public int compare(String a, String b) {
return a.split(",")[0].compareToIgnoreCase(b.split(",")[0]);
}
}
public static void main(String[] args) {
LinkedList<String> ll = new LinkedList<String>();
ll.add("TY12354d,sfasdf,asfasf,2.35123412E8");
ll.add("TY12354dsaf,asdffasd,asfasfafsd,12344.0");
ll.add("Pranish,pranishfilan,viper,1234");
System.out.println("Before sorting on ID:\n");
for (String s : ll) {
System.out.println(s);
}
Collections.sort(ll,new IDComparator());
System.out.println("\nAfter sorting on ID:\n");
for (String s : ll) {
System.out.println(s);
}
}
}
Output:
Before sorting on ID:
TY12354d,sfasdf,asfasf,2.35123412E8
TY12354dsaf,asdffasd,asfasfafsd,12344.0
Pranish,pranishfilan,viper,1234
After sorting on ID:
Pranish,pranishfilan,viper,1234
TY12354d,sfasdf,asfasf,2.35123412E8
TY12354dsaf,asdffasd,asfasfafsd,12344.0
This is not the prettiest code I've written. I especially don't like the comparator itself, with a hard coded index. However, it'll give you an idea of how to proceed with custom comparators.

Order the elements of array list in Java

I have an arraylist defined whose elements are say, [man, animal, bird, reptile]. The elements in the arraylist are non-mandatory. The list can even be empty.
I always need to give the output as [animal,man,reptile,bird]. Means, the order of the elements are to be maintained. Is there any way of doing in arraylist?
I thought I can do like
for (String listElement: customList) { //custom list variable holds all elements
if (listElement.equalsIgnoreCase("animal"){
newList.add(0, listElement);
} else if("man") {
newlist.add(1, listElement);
}
But I would want to know the best practice of doing. Can someone please help me on this?
You can define a custom sorting and use it to order your array (save the comparator somewhere, so you don't have to instantiate it many times):
List<String> definedOrder = // define your custom order
Arrays.asList("animal", "man", "reptile", "bird");
Comparator<String> comparator = new Comparator<String>(){
#Override
public int compare(final String o1, final String o2){
// let your comparator look up your car's color in the custom order
return Integer.valueOf(definedOrder.indexOf(o1))
.compareTo(Integer.valueOf(definedOrder.indexOf(o2)));
}
};
Collections.sort(myList, comparator);
Use a custom comparator:
Collections.sort(customList, comparator);
int i = 0;
for (String temp : customList) {
System.out.println("customList " + ++i + " : " + temp);
}
Custom comparator below:
public static Comparator<String> comparator = new Comparator<String>() {
public int compare(String str1, String str2) {
return orderOf(str1) - orderOf(str2);
}
private int orderOf(String name) {
return ((List)Arrays.asList("animal", "man", "reptile", "bird")).indexOf(name);
}
};
You can use Collections.sort(yourArrayList, new CustomComparator());
You need to create your own comparator for this, though, but it is easy.
public class CustomComparator implements Comparator<YourType>{
#Override
public int compare(YoyrType o1, YoyrType o2) {
// logic for ordering the list
}
}
arraylist is ordered.
maybe you want to insert element into the list.
could you create a new list every time when you have to insert and copy each of them?

How to use Collections.sort() in Java?

I got an object Recipe that implements Comparable<Recipe> :
public int compareTo(Recipe otherRecipe) {
return this.inputRecipeName.compareTo(otherRecipe.inputRecipeName);
}
I've done that so I'm able to sort the List alphabetically in the following method:
public static Collection<Recipe> getRecipes(){
List<Recipe> recipes = new ArrayList<Recipe>(RECIPE_MAP.values());
Collections.sort(recipes);
return recipes;
}
But now, in a different method, lets call it getRecipesSort(), I want to sort the same list but numerically, comparing a variable that contains their ID. To make things worse, the ID field is of the type String.
How do I use Collections.sort() to perform the sorts in Java?
Use this method Collections.sort(List,Comparator) . Implement a Comparator and pass it to Collections.sort().
class RecipeCompare implements Comparator<Recipe> {
#Override
public int compare(Recipe o1, Recipe o2) {
// write comparison logic here like below , it's just a sample
return o1.getID().compareTo(o2.getID());
}
}
Then use the Comparator as
Collections.sort(recipes,new RecipeCompare());
The answer given by NINCOMPOOP can be made simpler using Lambda Expressions:
Collections.sort(recipes, (Recipe r1, Recipe r2) ->
r1.getID().compareTo(r2.getID()));
Also introduced after Java 8 is the comparator construction methods in the Comparator interface. Using these, one can further reduce this to 1:
recipes.sort(comparingInt(Recipe::getId));
1 Bloch, J. Effective Java (3rd Edition). 2018. Item 42, p. 194.
Create a comparator which accepts the compare mode in its constructor and pass different modes for different scenarios based on your requirement
public class RecipeComparator implements Comparator<Recipe> {
public static final int COMPARE_BY_ID = 0;
public static final int COMPARE_BY_NAME = 1;
private int compare_mode = COMPARE_BY_NAME;
public RecipeComparator() {
}
public RecipeComparator(int compare_mode) {
this.compare_mode = compare_mode;
}
#Override
public int compare(Recipe o1, Recipe o2) {
switch (compare_mode) {
case COMPARE_BY_ID:
return o1.getId().compareTo(o2.getId());
default:
return o1.getInputRecipeName().compareTo(o2.getInputRecipeName());
}
}
}
Actually for numbers you need to handle them separately check below
public static void main(String[] args) {
String string1 = "1";
String string2 = "2";
String string11 = "11";
System.out.println(string1.compareTo(string2));
System.out.println(string2.compareTo(string11));// expected -1 returns 1
// to compare numbers you actually need to do something like this
int number2 = Integer.valueOf(string1);
int number11 = Integer.valueOf(string11);
int compareTo = number2 > number11 ? 1 : (number2 < number11 ? -1 : 0) ;
System.out.println(compareTo);// prints -1
}
Use the method that accepts a Comparator when you want to sort in something other than natural order.
Collections.sort(List, Comparator)
Sort the unsorted hashmap in ascending order.
// Sorting the list based on values
Collections.sort(list, new Comparator<Entry<String, Integer>>() {
public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2)
{
return o2.getValue().compareTo(o1.getValue());
}
});
// Maintaining insertion order with the help of LinkedList
Map<String, Integer> sortedMap = new LinkedHashMap<String, Integer>();
for (Entry<String, Integer> entry : list) {
sortedMap.put(entry.getKey(), entry.getValue());
}

In java, is there a way to search for a specific field of a class stored in a linked list?

I wrote a class that is to be stored in a linkedlist, with 3 fields in the class. One of these fields is a String, which I would like to search for in the linked list.
Example
LinkedList
Obj1
String name = "first";
int age = 2;
int size = 4;
Obj2
String name = "second";
int age = 3;
int size = 6;
Obj3
String name = "third";
int age = 5;
int size = 8;
If this is the linkedlist storing these three objects with the given fields, is there a way to search the linked list for the object with the name "second"?
You can search for an item in the list by iteration
// Iterate over each object within the list
for(YourClass obj : yourLinkedList) {
// Check if the object's name matches the criteria, in this case, the name
// of the object has to match "second"
if (obj.name.equals("second")) {
// If we are within this block, it means that we found the object that has
// its name set as "second".
return obj;
}
}
You could also make a method to make things more elegant
public YourClass findByName(String name) {
for(YourClass obj : yourLinkedList) {
if (obj.name.equals(name)) {
return obj;
}
}
return null;
}
And use it the following way
YourClass object = findByName("second");
The easiest way to do this would be to of course, iterate through each element in the collection, checking if it matched your filter condition, and selecting the matches found. However this gets tedious the more times you need to do it, and the more complex your filter condition is. I would recommend utilizing pre-existing libraries to get the task done efficiently. Here is an example using Google-Collections:
final List<SomeObj> listObjs = Arrays.asList(
new SomeObj("first", 2, 4), new SomeObj("second", 3, 6),
new SomeObj("third", 5, 8));
final Iterable<SomeObj> filtered = Iterables.filter(listObjs,
new Predicate<SomeObj>() {
#Override
public boolean apply(final SomeObj obj) {
return "second".equals(obj.getName());
}
});
for (final SomeObj obj : filtered) {
System.out.println(obj);
}
The code shown would select all objects in the list with a name property of "second". Obviously, the predicate doesn't have to be an anonymous inner class - if you needed to reuse it you would just break it out to a standalone class.
Here's another way to implement a Comparator (just in case it helps).
I find it's easier to understand if you implement the Comparator explicitly:
class PersonAgeComparator implements Comparator<Person> {
#Override
public int compare(Person p1, Person person2) {
return p1.getAge().compareTo(p2.getAge());
}
}
You might use the above like this:
Comparator ageComparator = new PersonAgeComparator();
List<Person> personList = // populate list somehow
Person fourYearOld = new Person();
fourYearOld.setAge(4);
for (Person p : personList) {
if (ageComparator.compare(fourYearOld, p) == 0) {
System.out.println(p.getName() + " is 4 years old");
}
}
This doesn't make much sense for this simple example.
It would be ideal if you had several complicated ways to compare people (by height, by adjusted income, by how many states they've lived in, etc...).
Take a look at the java.util.Comprator interface. You can write a method that iterates over a List and uses a comparator to find the one you are after.
Something like (not compiled):
for(final T value : list)
{
if(comparator.compare(value, desired) == 0)
{
// match
}
}
In your comparator you have it perform whatever comparison you want.
Here is a working example:
public class JavaApplication4
{
public static void main(String[] args)
{
final List<Data> list;
final List<Data> a;
final List<Data> b;
list = new ArrayList<Data>();
list.add(new Data("Foo", 1));
list.add(new Data("Bar", 10));
list.add(new Data("Car", 10));
a = find(list,
new Data("Bar", 0),
new Comparator<Data>()
{
#Override
public int compare(final Data o1,
final Data o2)
{
return (o1.name.compareTo(o2.name));
}
});
b = find(list,
new Data(null, 10),
new Comparator<Data>()
{
#Override
public int compare(final Data o1,
final Data o2)
{
return (o1.count - o2.count);
}
});
System.out.println(a.size());
System.out.println(b.size());
}
private static List<Data> find(final List<Data> list,
final Data desired,
final Comparator<Data> comprator)
{
final List<Data> results;
results = new ArrayList(list.size());
for(final Data data : list)
{
if(comprator.compare(desired, data) == 0)
{
results.add(data);
}
}
return (results);
}
private static class Data
{
private final String name;
private final int count;
Data(final String nm,
final int c)
{
name = nm;
count = c;
}
}
}
And here is a generic version of the find method. Using this method you would never have to write the find method again, using a method that embeds the logic for matching in the iteration code means that you would have to re-write the iteration logic for each new set of matching logic.
private static <T> List<T> find(final List<T> list,
final T desired,
final Comparator<T> comprator)
{
final List<T> results;
results = new ArrayList(list.size());
for(final T value : list)
{
if(comprator.compare(desired, value) == 0)
{
results.add(value);
}
}
return (results);
}
You can go through it and get it done or there's another way.
You need to override the equals method in your class (and the hashcode method as well).
After you override the equals to your desire, in this case to compare the names, create a new object with the same name and call the remove(Object o) method of the LinkedList and get the object.
You should note that with this approach you objects equality will be defined by name and that the entry will be removed from the LinkedList

How to sort a List<Enum, Collection> by order of an enum?

Enum:
public enum ComponentType {
INSTRUCTION, ACTION, SERVICE, DOMAIN, INTEGRATION, OTHER, CONTEXT;
}
Class A :
public class A
{
String name;
ComponentType c;
public A(String name, ComponentType c)
{
this.name = name;
this.c = c;
}
}
Code:
List<A> l = new ArrayList<A>();
l.add(new A("ZY", ACTION));
l.add(new A("ZY0", INSTRUCTION));
l.add(new A("ZY1", DOMAIN));
l.add(new A("ZY2", SERVICE));
l.add(new A("ZY3", INSTRUCTION));
l.add(new A("ZY4", ACTION));
How to sort list according to enum order?
You should simply delegate to the enum compareTo method which is already provided and reflects the declaration order (based on the ordinal value):
Collections.sort(list, (a1, a2) -> a1.getType().compareTo(a2.getType()));
Or, if you think that the component type provides the "natural order" for your elements, you can make the A class itself implement Comparable and also delegate the compareTo method to the ComponentType one.
Make A implement Comparable. If you want to sort by the names of the enums, use this compareTo method:
public int compareTo(A a) {
return a.c.getName().compareTo(c.getName());
}
If you want to sort by the order you have typed your enums, compare the ordinal values:
public int compareTo(A a) {
return a.c.ordinal().compareTo(c.ordinal());
}
I had the same problem but I couldn't modified my Enum class and the order was wrong. That's why I couldn't use simple compareTo on enum object. The solution is very simple, just assign the int value for every Enum field and then compare it:
public class MyComparator implements Comparator<A> {
#Override
public int compare(A o1, A o2) {
return Integer.compare(getAssignedValue(o1.getComponentType()), getAssignedValue(o2.getComponentType()));
}
int getAssignedValue(ComponentType componentType) {
switch (componentType) {
case OTHER:
return 0;
case CONTEXT:
return 1;
case SERVICE:
return 2;
case DOMAIN:
return 3;
case INTEGRATION:
return 4;
case ACTION:
return 5;
case INSTRUCTION:
return 6;
default:
return Integer.MAX_VALUE;
}
}
}
And then:
Collections.sort(list, new MyComparator);
According to java.util.Collections.sort, one way to do this is:
Make class A implement the Comparable interface, this includes writing a int compare(A other) method.
Call Collections.sort(l);
If it is required to sort the class based on ENUM, for consistency purpose we must use the ENUM's compareTo(which if final) method.
Adding this method to A class will help and keep the consistent behaviour.
#Override
public int compareTo(A o) {
return this.c.compareTo(o.c);
}
It appears you should be using an EnumMap as they are naturally sorted by the key.
public static void add(Map<ComponentType, List<A>> map, A a) {
List<A> as = map.get(a.c);
if(as == null) map.put(a.c, as = new ArrayList<A>());
as.add(a);
}
Map<ComponentType, List<A>> map = new EnumMap<ComponentType, List<A>>(ComponentType.class);
add(map, new A("ZY", ComponentType.ACTION));
add(map, new A("ZY0", ComponentType.INSTRUCTION));
add(map, new A("ZY1", ComponentType.DOMAIN));
add(map, new A("ZY2", ComponentType.SERVICE));
add(map, new A("ZY3", ComponentType.INSTRUCTION));
add(map, new A("ZY4", ComponentType.ACTION));
Enum compareTo seems to be final and cant be overriden
Why is compareTo on an Enum final in Java?
Just do Collections.sort() which will order the list in enum order as you need
Here is what you have to do:
List<A> l = new ArrayList<A>();
l.add(new A("ZY", ComponentType.ACTION));
l.add(new A("ZY0", ComponentType.INSTRUCTION));
l.add(new A("ZY1", ComponentType.DOMAIN));
l.add(new A("ZY2", ComponentType.SERVICE));
l.add(new A("ZY3", ComponentType.INSTRUCTION));
l.add(new A("ZY4", ComponentType.ACTION));
Collections.sort(l, new Comparator<A>()
{
#Override
public int compare(A o1, A o2)
{
return o1.c.toString().compareTo(o2.c.toString());
}
});
First of all, you don't have a List<Enum, Collection> as this is impossibile, you have a List<A> and shoud declare it as follows:
List<A> list = new LinkedList<>();
You are trying to instantiate in interface, which is not possible and is a compile time error.
If you want to sort a List of A's you should make a comparable:
public class A implements Comparable<A>
and override the compareTo() method as follows:
#Override
public int compareTo(A other) {
return c.ordinal() - other.c.ordinal();
}
To sort your List you can call:
Collections.sort(list);
First of all - start using Generics. So your code woudl be
List<A> l = new ArrayList<A>();
And for your question, let your A class implement Comparable and override the method compareTo where you can put the expression for sorting. Example here

Categories

Resources