I have a class Arraylist contains value
String word, String expandedword, double confidence, double support
I want to sort the arraylist based on the confidence, and then based on the support.
I have succeed sort the arraylist based on confidence, but i failed to make a new method to sort the arraylist based on the support
this is my code to sort it based on confidence
public class ExpandedTerm implements Comparable<ExpandedTerm> {
String word;
String expandedWord;
double support;
double confidence;
public ExpandedTerm (String word,String expandedWord, double confidence,double support){
this.word = word;
this.expandedWord = expandedWord;
this.support = support;
this.confidence = confidence;
}
public String getWord(){
return word;
}
public String expandedWord(){
return expandedWord;
}
public Double getSupport(){
return support;
}
public Double getConfidence(){
return confidence;
}
#Override
public int compareTo(ExpandedTerm conf) {
return new Double(this.confidence).compareTo(new Double(conf.confidence));
}
I failed to make another method like compareTo, to sort it based on the support value.
How to sort it first by the confidence, and then make another method to sort it by the support value?
User Comparator for this. As compaarble provide functionality to sort on single type basis.
here is link where you found when to use comparable and comapartor
http://iandjava.blogspot.in/2012/10/comparable-and-comparator.html
Use multiple comparartor
one for confidence
public class ConfidanceComparator implements Comparator<ExpandedTerm> {
#Override
public int compare(final ExpandedTerm o1, final ExpandedTerm o2) {
return new Double(o1.confidence).compareTo(new Double(o2.confidence));
}
}
one for support
public class SupportComparator implements Comparator<ExpandedTerm> {
#Override
public int compare(final ExpandedTerm o1, final ExpandedTerm o2) {
return new Double(o1.support).compareTo(new Double(o2.support));
}
}
and use Collections.sort(<List>, <comparator>) adn you will get the desired list.
THis is only required when you want to sort either on confidance basis or support basis.
But if you required then first sort on confidance basis and if confidance is equal then check for support basis. then comparable is sufficient and is
public int compareTo(ExpandedTerm conf) {
int compare = new Double(this.confidence).compareTo(new Double(conf.confidence));
if (compare == 0) {
compare = new Double(this.support).compareTo(new Double(conf.support));
}
return compare;
}
Try this code for your compareTo method:
#Override
public int compareTo(ExpandedTerm other) {
Double thisConfidence = new Double(getConfidence());
Double otherConfidence = new Double(other.getConfidence());
int compare = thisConfidence.compareTo(otherConfidence);
if (compare == 0) {
Double thisSupport = new Double(getSupport());
Double otherSupport = new Double(other.getSupport());
compare = thisSupport.compareTo(otherSupport);
}
return compare;
}
Basically only compare "support" if "confidence" is equal.
I saw your reply that you want to sort once and sort again except differently, so I'm assuming you want to add a custom Comparator when you sort. Is this what you're looking for?
public static void main(String[] args) {
ExpandedTerm term1 = new ExpandedTerm("a", "b", 1, 4);
ExpandedTerm term2 = new ExpandedTerm("c", "d", 3, 2);
List<ExpandedTerm> list = new ArrayList();
list.add(term1);
list.add(term2);
Collections.sort(list);
System.out.println(list);
Collections.sort(list, new Comparator<ExpandedTerm>() {
#Override
public int compare(ExpandedTerm o1, ExpandedTerm o2) {
return new Double(o2.confidence).compareTo(new Double(o1.confidence));
}
});
System.out.println(list);
}
Here's the output
[ExpandedTerm#2eeb3c84, ExpandedTerm#55d2162c]
[ExpandedTerm#55d2162c, ExpandedTerm#2eeb3c84]
Some other tips: make sure you implement the toString(), hashCode(), and equals() functions for your ExpandedTerm. These are essential for debugging and also for use in other Collections like HashMap, etc.
Related
Say I have:
class Item {
int id;
int type;
}
I can do this:
List<Item> items;
Item itemToFind;
Comparator<Item> itemComparator;
Collections.binarySearch(items, itemToFind, itemComparator);
However, say that instead of the whole object, I'm only given a property of the object, say type for the above example. Assuming the list is sorted by that property, is there a standard method in Java or some established library to do something to this effect:
List<Item> items;
Function<Item, Integer> typeExtractor = Item::getType;
int typeToFind;
Comparator<Integer> typeComparator = Integer::compare;
binarySearch(items, typeExtractor, typeToFind, typeComparator);
without additional overhead (e.g. converting List<Item> to List<Integer> to call Collections.binarySearch on or similar)?
Your problem is that in a Collection<T> the binary search implementation of java allows to search only for items of type T. In order to search for another type which is a part of T, you can do the following:
Wrap the other type inside T, in your case this should look like this:
List<Item> items;
int typeToFind;
Item itemToFind = new Item(/* random value for id */ 0, typeToFind);
int index = binarySearch(items, itemToFind , (a, b) -> a.getType() - b.getType());
Some important notes to add here:
- the comparison of items should depend only and only on `type`, otherwise you may end up with some nasty bugs;
- the list of items should be sorted. The sorting should depend only and only on `type`(basically using the same comparator as before)
Create a new list from the initial list:
List<Items> items;
int typeToFind
int index = binarySearch(items.stream.map(item -> item.getType()).collect(Collectors.toList()), itemToFind);
As far as I know, the standard library for Java does not provide binary search implementation with a comparator for key equality. If these options does not satisfy you, probably you should search for a library or implement your own search.
The comparator still would be Comparator<Item>. What you would change is the implementation of the comparator to evaluate upon the type instead of the id.
Comparator<Item> comparator = new Comparator<Item>(){
public int compare(Item a, Item b)
{
return a.getType() - b.getType();
}
}
Item, would need to have the getter for type or the attribute made public. The same if using the id.
However, not sure how you suggest I would call
Collections.binarySearch
The usage doesn't change (what changes is how the comparison is done inside the comparator object):
Item itemToFind = new Item();
itemToFind.setType(typeToFind);
Collections.binarySearch(items, itemToFind, comparator );
After some thought on the subject:
An alternative to use an Item as a needle is to base the Comparator on an Interface that Item and the needle implement.
An interface to return int values:
public interface Intgettable{
public int getInt();
}
Item should have to implement this interface:
public class Item implements Intgettable{
private int id;
private int type;
public void setId(int id){
this.id = id;
}
public void setType(int type){
this.type = type;
}
public int getId(){
return id;
}
public int getType(){
return type;
}
public int getInt(){
return type;
}
}
The key to search will be an Intgettable which can be created:
1 - Using a class that extends Intgettable.
public static class MyItemKey implements Intgettable{
private int value;
public MyItemKey(int v){
this.value = v;
}
#Override
public int getInt(){
return value;
}
}
MyItemKey typeToFind = new MyItemKey(6);
2 - As an anonymous class inside the method.
Intgettable typeTofind = new Intgettable(){
private int value = 6;
public int getInt(){
return value;
}
};
3 - Or using the lambda version:
Intgettable typeTofind = ()->{return 6;};
The Comparator will be:
Comparator<Intgettable> comparator = new Comparator<Intgettable>(){
public int compare(Intgettable a, Intgettable b){
return a.getInt() - b.getInt();
}
};
And finally use it in the binary search:
Collections.binarySearch(items, typeToFind, comparator );
How to insert both String's and Integers in the same Queue ?
Please look at the below program, I have created two objects (q, q1). Can we insert strings and integers in one Queue?
import java.util.*;
public class Solution {
public void myMethod() {
Queue<Integer> q=new PriorityQueue<>();
Queue<String> q1=new PriorityQueue<>();
q.add(3);
q1.add("Eswar");
System.out.println(q);
System.out.println(q1);
}
public static void main(String...args) {
Solution s=new Solution();
s.myMethod();
}
}
You can:
Queue<Object> q=new PriorityQueue<>();
But you have to care about correct types now.
You can do it without generics, but its not recommended as you can have runtime exceptions:
List list = new ArrayList();
list.add("Hi");
String s = (String) list.get(0);
It is not suggested to have two different types in the same Collection with Generics using Object or RawType as it might lead to runtime errors,
Option 1 - Try to keep the Integer also in String representation If it fills your purpose,
Queue<String> q1=new PriorityQueue<>();
q1.add(String.valueOf(1));
q1.add("Eswar");
System.out.println(q1);
Option 2 - Create your own type which contains both and manage in through enum if only you have to use PriorityQueue. Please note you have to add your own Comparator,
Enum for DataType
enum DataType{
INTEGER,
STRING
}
Your Own DataType class
class MyData implements Comparable<MyData>{
private Integer intValue;
private String stringValue;
private DataType type;
public MyData(Integer intValue) {
this.intValue=intValue;
type=DataType.INTEGER;
}
public MyData(String stringValue) {
this.stringValue=stringValue;
type=DataType.STRING;
}
public Integer getIntValue() {
return intValue;
}
public String getStringValue() {
return stringValue;
}
public DataType getType() {
return type;
}
#Override
public String toString() {
return type==DataType.INTEGER?intValue.toString():stringValue;
}
#Override
public int compareTo(MyData data) {
//Add your comparator here based on your criteria
return 0;
}
}
And the implementation
Queue<MyData> q1=new PriorityQueue<>();
q1.add(new MyData(1));
q1.add(new MyData("Eswar"));
System.out.println(q1);
Using a Queue<Object> you'll be able to add any type you want, becauseObject is a supertpe of every one. But you cannot use any implementation, like PriorityQueue because it requires a sort on the elements, and different types are not comparable together. An ArrayDeque would be good for that.
Queue<Object> q = new ArrayDeque<>();
q.add(5);
q.add("Foo");
q.add(5d);
Workable Demo
Pre-TL;DR: Need to see if a comparator is an instance of (or equal to) another comparator, even if it is reversed.
Hello, I think this problem is very simple but I am just thinking too much into it.
I have a program that allows a user to sort lists by different comparators. The user can choose ascending or descending order. Since comparators are by default in ascending order, all I do to achieve descending order is create a new reversed comparator:
Comparator newReversedCMP = Collections.reverseOrder(Comparator originalComp)
Another part of the program saves the last comparator used so that the user can sort or view the last comparator used. Let's say I have comparators dealing with names and salaries and a method that returns what it deals with, for example:
if (lastCMPUsed.equals(new NameComparator()){
return "Name";
}
if (lastCMPUsed.equals(new SalaryComparator()){
return "Salary";
}
Sorry for the long intro but my issue is that I also want to return "Name" or "Salary" even if it's a reverse of the original Name or Salary comparator. If lastCMPUsed is a reversedOrder CMP, then it does not find them equal.
I have tried this but with no success:
//lastCMPUsed = Collections.reversedOrder(new NameComparator());
if (lastCMPUsed.equals(Collections.reverseOrder(new NameComparator())
return "Name";
This does not return "Name" and sees them as not equal.
My equals method in each comparator is a simple instanceof check.
Thanks for reading.
If you need some particular definition of equality besides one defined by the supertype, you should write a class structure that will properly do this for you.
For example:
public abstract class PersonComparator implements Comparator<Person> {
private final boolean isReversed;
private PersonComparator(boolean isReversed) {
this.isReversed = isReversed;
}
public boolean isReversed() {
return isReversed;
}
#Override
public int compare(Person lhs, Person rhs) {
return isReversed ? compareImpl(rhs, lhs) : compareImpl(lhs, rhs);
}
public abstract String getComparison();
protected abstract int compareImpl(Person lhs, Person rhs);
public static final class Name extends PersonComparator {
private Name(boolean isReversed) { super(isReversed); }
#Override
protected int compareImpl(Person lhs, Person rhs) {
return lhs.getName().compareTo(rhs.getName());
}
#Override
public String getComparison() {
return "Name";
}
}
public static final Name NAME = new Name(false);
public static final Name NAME_REVERSE = new Name(true);
}
The equality here is that:
NAME.getClass() == NAME_REVERSE.getClass() // true
NAME instanceof PersonComparator.Name //
&& // true
NAME_REVERSE instanceof PersonComparator.Name //
NAME == NAME_REVERSE // false
NAME.equals(NAME_REVERSE); // false
NAME.getComparison() //
.equals(NAME_REVERSE.getComparison()) // true
Note that I did not need to override equals and hashCode, because there is only a single instance of each possible Comparator.
I want to sort an ArrayList by a property. This is my code...
public class FishDB{
public static Object Fish;
public ArrayList<Fish> list = new ArrayList<Fish>();
public class Fish{
String name;
int length;
String LatinName;
//etc.
public Vis (String name) {
this.name = name;
}
}
public FishDB() {
Fish fish;
fish = new Fish("Shark");
fish.length = 200;
fish.LatinName = "Carcharodon Carcharias";
fish = new Fish("Rainbow Trout");
fish.length = 80;
fish.LatinName = "Oncorhynchus Mykiss";
//etc.
}
}
}
Now I want in want to sort this ArrayList by a property e.g the latinname in another activity. But I don't know how to do that. Does anybody know how?
You need to implement a Comparator, for instance:
public class FishNameComparator implements Comparator<Fish>
{
public int compare(Fish left, Fish right) {
return left.name.compareTo(right.name);
}
}
and then sort it like this:
Collections.sort(fishes, new FishNameComparator());
You can simply do it by this code:
Collections.sort(list, new Comparator<Fish>() {
public int compare(Fish o1, Fish o2) {
return o1.name.compareTo(o2.name);
}
});
Kotlin code
list.sortWith(Comparator { o1, o2 -> o1.name!!.compareTo(o2.name!!) })
There are multiple options how to achieve the same goal.
The easiest solutions would be utilizing Java 8 features:
Collections.sort(Fish, (t1, t2) -> t1.name().compareTo(t2.name()));
I have created a Vector object to store data in Table object as Vector<Table>. Vector<Table> contains components as below.
[Vector<Record> records, String tableName, String keyColumnName, int recordCount, int columnCount]
I need to sort tableName in above Vector to my own order and return Vector<Table> with sorted tableNames for other processes.
I have wrote method as below.
private Vector<Table> orderTables(Vector<Table> loadTables) {
List<String> tableNames = new ArrayList<String>();
for (Table table : loadTables) {
String tblName = table.getTableName();
tableNames.add(tblName);
}
Collections.sort(tableNames, new MyComparable());
return null;
}
But I have no idea about how to write Comparator to this. My own sort order is stored in .properties file. I can read it and get value. But I have no idea about how to compare it.
How could I do it?
Before clarification
You need to write a Comparator for Table objects that delegates to the tableName's comparator:
new Comparator<Table>() {
#Override public int compare(Table one, Table two) {
return one.getTableName().compareTo(two.getTableName());
}
}
Note that this will consider Tables that have the same name to be equal. This can mess things up if you put these tables in a HashMap or HashSet. To avoid this, you can detect this case and return one.hashCode() - two.hashCode() if the table names are the same.
Guava's ComparisonChain is a convenient way to write such multi-stage comparisons:
new Comparator<Table>() {
#Override public int compare(Table one, Table two) {
return ComparisonChain.start()
.compare(one.getTableName(), two.getTableName())
.compare(one.hashCode(), two.hashCode())
.result();
}
}
After clarification
Okay, the question is to impose a predefined sorting order rather than sorting the Tables by name. In that case, you need to make a Comparator that is aware of the ordering defined in the .properties file.
One way to achieve this is to initialize a mapping of table names to sorting order indices, and refer that mapping during the comparison. Given the property value:
SORT_ORDER = SALES,SALE_PRODUCTS,EXPENSES,EXPENSES_ITEMS
The mapping should look like:
{
SALES: 0,
SALE_PRODUCTS: 1,
EXPENSES: 2,
EXPENSES_ITEMS: 3
}
Here's what the comparator would look like:
private static class PredefinedOrderComparator implements Comparator<Table> {
public PredefinedOrderComparator() {
// Initialize orderIndex here
}
private final Map<String, Integer> orderIndex;
#Override public int compare(Table one, Table two) {
return orderIndex.get(one.getTableName()) - orderIndex.get(two.getTableName());
}
}
To populate orderIndex from the property value, you need to:
Get the comma-separated list using getProperty() as you mentioned
Split that value on comma (I recommend using Guava's Splitter, but String.split or others will work too)
Initialize a new HashMap<String, Integer> and an int index = 0
Iterate through the split tokens, map the current token to index and increment index
Note the implicit assumption that none of the table names have a comma in it.
public class MyComparable implements Comparator<Table>{
#Override
public int compare(Table table1, Table table2) {
return (table1.getTableName().compareTo(table2.getTableName());
}
}
make sure that you have overridden the hashcode and equals in Table class to achieve this.
I wrote you a very simple example on how to work with a Comparator. If you create a class called Main, copy paste below contents in it, compile and run it, you can see what's going on.
A comparator just needs to implement an interface. For this it needs to implement one method (public int compare(T arg0, T arg1). There you specify how a collection will get sorted; in this case according to the alfabet.
I hope this helps you.
import java.util.*;
public class Main {
public static void main(String[] args) {
System.out.println("Start\n");
List<Item> items = new ArrayList<Item>();
for(String s : new String[]{"mzeaez", "xcxv", "hjkhk", "azasq", "iopiop"}) {
items.add(createItem(s));
}
System.out.println("Items before sort:");
System.out.println(Item.toString(items));
Collections.sort(items, new ItemComparator());
System.out.println("Items after sort:");
System.out.println(Item.toString(items));
System.out.println("End");
}
private static Item createItem(String s) {
Item item = new Item();
item.setS(s);
return item;
}
}
class Item {
private String s;
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
#Override
public String toString() {
return "Item: " + s;
}
public static String toString(Collection<Item> items) {
String s = "";
for(Item item : items) {
s += item + "\n";
}
return s;
}
}
class ItemComparator implements Comparator<Item> {
#Override
public int compare(Item item1, Item item2) {
return item1.getS().compareTo(item2.getS());
}
}