Implementing comparator multiple times in a single class file [duplicate] - java

This question already has answers here:
How do I make 2 comparable methods in only one class?
(3 answers)
Closed 8 years ago.
I have some code to sort paths by date modified. I want to also write some code to sort the paths in reverse order, and might later want to add some other sorting methods. Is there any way to do all the sorting from a single class file? Or do I have to create another class PathSortByDateReverse, PathSortByCreated, PathSortByFoo, etc. Also, how would I use the different sorting methods?
import java.nio.file.Path;
import java.util.Comparator;
public class PathSortByDate implements Comparator<Path> {
#Override
public int compare(Path first, Path second) {
long seconddate = second.toFile().lastModified(); // get just the filename
long firstdate = first.toFile().lastModified();
if (firstdate == seconddate) {
return 0;
} else if (firstdate > seconddate) {
return 1;
} else {
return -1;
}
}
}
I then call it from the other class with:
public static ArrayList<Path> sortArrayListByDate(ArrayList<Path> pathlist) {
Collections.sort(pathlist,new PathSortByDate());
return pathlist;
}

Why not go for an anonymous inner classes?
public static final Comparator<Person> ID_DESC
= new Comparator<Person>() {
public int compare(Person p1, Person p2) {
return -1 * p1.getId().comparedTo(p2.getId());
// reversed order
}
};

I would usually do it like this. Notice, the constructor is "private" and there is a "public factory method" to get an instance. There will ever exist two PathComparator instances at any given point. This is a big deal if you are into optimizing your code and using best practices.
import java.nio.file.Path;
import java.util.Comparator;
final public class PathComparator implements Comparator<Path> {
// comparator for in order
final private static PathComparator ascendingOrderComparatorDate = new PathComparator(true);
// comparator for reverse order
final private static PathComparator descendingOrderComparatorDate = new PathComparator(false);
final private int isAscendingOrderInt;
final public PathComparator getPathComparator(boolean isAscendingOrder) {
return isAscendingOrder ? ascendingOrderComparatorDate : descendingOrderComparatorDate;
}
private PathComparator(boolean isAscendingOrder) {
this.isAscendingOrderInt = isAscendingOrder ? 1 : -1;
}
#Override
public int compare(Path first, Path second) {
// for optimization (not required but highly recommended)
if(first == second) return 0;
long seconddate = second.toFile().lastModified(); // get just the filename
long firstdate = first.toFile().lastModified();
if (firstdate == seconddate) {
return 0;
} else if (firstdate > seconddate) {
return isAscendingOrderInt * 1;
} else {
return isAscendingOrderInt * -1;
}
}}

you dont need to make the reverse comparator, just make it and reverse it with
Collections.reverseOrder()

Related

Selecting object items with same value from a list of objects

I have a array or list which contains a timestamp, an Id and other data.
Something like this:
public class CanMessage {
public int MsgID ;
public byte length ;
public byte [] dataByte = new byte[8];
}
public class CanTrace {
public float timestamp ;
public CanMessage canMsg ;
}
Question is how can I make a list or Array of CanTrace, in which I can make selection on List items that have a certain MsgID. So that for example I can make a plot of the dataByte with one and the same MsgID.
Or is this only possible by searching with a while loop through for example a ct object create with
List ct =new ArrayList();
If MsgID is unique, then it would be useful to use a HashMap with a key,value pair of (MsgID,CanTrace)
Then you would be able to access the dataByte using -
(CanTrace)(map.get(MsgID)).dataByte
If you are using Java 8 you could directly use the filter method as listOfCanMessages.stream().filter(b -> b.MsgID == 1).
In other case you can either try Guava or Lamdaj
For example.
import static ch.lambdaj.Lambda.having;
import static ch.lambdaj.Lambda.on;
import static ch.lambdaj.Lambda.select;
import static org.hamcrest.core.IsEqual.equalTo;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
public class FilterSample {
public static void main(String[] args) {
List<CanMessage> list = new ArrayList<CanMessage>();
CanMessage c = new CanMessage();
c.MsgID = 1;
CanMessage c2 = new CanMessage();
c2.MsgID = 2;
CanMessage c3 = new CanMessage();
c3.MsgID = 1;
CanMessage c4 = new CanMessage();
c4.MsgID = 4;
list.add(c);
list.add(c2);
list.add(c3);
list.add(c4);
//Java 8 example
List<CanMessage> filteredList1 = list.stream().filter(b -> b.MsgID == 1).collect(Collectors.toList());
System.out.println(filteredList1);
//Guava example
List<CanMessage> filteredList2 = Lists.newArrayList(Collections2.filter(
list, new Predicate<CanMessage>() {
#Override
public boolean apply(CanMessage input) {
if (input.MsgID == 1) {
return true;
}
return false;
}
}));
System.out.println(filteredList2);
//Lambdaj example. Please note 6 down vote accepted Lambdaj wraps your (non-final) classes with a Proxy
// and intercepts METHOD invocations on them. That means it cannot work on fields but only on methods. So
// you cannot access MsgID directly, you'll have to provide a getter method
List<CanMessage> filteredList3 = select(list, having(on(CanMessage.class).getMsgID(), equalTo(1)));
System.out.println(filteredList3);
}
}
thanks for the fast answer.
I ask a collegue and he came with this Idea:
public void OrderedMsg(int Id){
List<CanTrace> traces = new ArrayList<CanTrace>();
Comparator<CanTrace> comparator = new Comparator<CanTrace>() {
public int compare(CanTrace o1, CanTrace o2) {
if (o1.time < o2.time) {
return -1;
} else if (o1.time > o2.time) {
return 1;
} else {
return 0;
}
}
};
for (CanTrace trace : traces) {
int id = trace.canMsg.MsgID;
if (!orderedMap.containsKey(id)) {
orderedMap.put(id, new TreeSet<CanTrace>(comparator));
}
orderedMap.get(id).add(trace);
}
}

Create method for Iterator [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
Can describe to me why my Iterator does not work. JDeveloper says that I must create a method for Iterator, but I don't have a clue what the program means with that. Therefore I ask for your help. The Program looks like this:
TestOrder:
package hej;
import java.util.*;
public class TestOrder {
public static void main(String[] args) {
OrderRegister orderregister = new OrderRegister();
Order order1 = new Order("123","Kop");
Order order2 = new Order("456","Salj");
Order order3 = new Order("789","Kop");
orderregister.addOrder(order1);
orderregister.addOrder(order2);
orderregister.addOrder(order3);
System.out.println(orderregister.sokOrder("123").getKopsalj());
orderregister.raderaOrder("456");
Order tmpOrder = orderregister.sokOrder("456");
if (tmpOrder == null) {
System.out.println("Fungerar!");
}
else{
System.out.println("Why u lie?");
}
System.out.println(orderregister.sokOrder("123").getKopsalj());
orderregister.sokOrder("123").setKopsalj("Salj");
System.out.println(orderregister.sokOrder("123").getKopsalj());
Iterator<Order> i=orderregister.iterator();
while(i.hasNext()){
System.out.println(i.next());
}
}
}
Order:
package hej;
import java.util.Iterator;
public class Order {
private String ordernr;
private String kopsalj;
public Order(String newOrdernr, String newKopsalj) {
setOrdernr(newOrdernr);
setKopsalj(newKopsalj);
}
public void setOrdernr(String ordernr) {
this.ordernr = ordernr;
}
public String getOrdernr() {
return ordernr;
}
public void setKopsalj(String kopsalj) {
this.kopsalj = kopsalj;
}
public String getKopsalj() {
return kopsalj;
}
public String toString()
{
return "Order: " + this.ordernr+", "+"Manover: "
+this.kopsalj;
}
}
OrderRegister:
package hej;
import java.util.ArrayList;
import java.util.Iterator;
public class OrderRegister {
private ArrayList<Order> orderArrayList;
public OrderRegister() {
orderArrayList = new ArrayList<Order>();
}
// Lagg till Order
public void addOrder(Order newOrder) {
orderArrayList.add(newOrder);
}
// Sok Order
public Order sokOrder(String ordernrSok) {
Order tmpOrder = null;
int i = 0;
boolean found = false;
while (i < orderArrayList.size() && !found) {
tmpOrder = orderArrayList.get(i);
if (tmpOrder.getOrdernr().equals(ordernrSok)) {
found = true;
}
i++;
}
if (!found) {
tmpOrder = null;
}
return tmpOrder;
}
// Ta bort Order
public void raderaOrder(String ordernrRadera) {
Order tmpOrder = null;
int i = 0;
boolean found = false;
while (i < orderArrayList.size() && !found) {
tmpOrder = orderArrayList.get(i);
if (tmpOrder.getOrdernr().equals(ordernrRadera)) {
orderArrayList.remove(i);
found = true;
}
i++;
}
}
// andra Orderuppgifter
public void setOrderUppgifter(String ordernr, String newKopsalj){
Order order = sokOrder(ordernr);
if (order != null) {
order.setKopsalj(newKopsalj);
}
}
}
You need to let the OrderRegister class implement Iterable.
T is the iterator data type, which is Order in your case.
So you get:
public class OrderRegister implements Iterable<Order>
The Iterable interface, requires you to define an iterator() method which returns an Iterator<E> object. In your case you do not require to create such an class, as you can grab the iterator object directly from your ArrayList:
public Iterator<Order> iterator() {
return orderArrayList.iterator();
}
Now you can use your class in this way:
for(Order order: orderregister) {
System.out.println(order.getKöpsälj());
}
Note: your while-loop will also still work
See http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Iterator.html.
For every iterator, you need to implement methods hasNext, next and remove.
Plus, your class orderregister doesn't have any method iterator(). You either need to inherit form a class that already has it implemented or you need to implement it by yourself.
let OrderRegister implements the Iterable interface and implement iterator than()
there you just can delegate to orderArrayList.iterator()
I assume your problem is this line:
Iterator<Order> i=orderregister.iterator();
because there is no method iterator() in your class OrderRegister.
Two solutions:
A) add the method iterator() (it could probably just do return orderArrayList.iterator();)
B) instead of wrapping an ArrayList, extend it!
public class OrderRegister extends ArrayList<Order> {
// No more orderArrayList!
}

Better way to map from String constants to int constants in Java

I have a load of images of musical symbols which I need to do some processing on and for each one I need to get the integer code corresponding to its file name. There are 23 possible file name strings and 23 integer code and there are many images with the same name under different directories.
The solution I have so far is given (abbreviated) below. I have just defined a load of int and String constants and then written a method which is just a huge chain of if statements to do the translation.
What would be a better way to achieve the same effect? The way I've done it seems really awful! I thought about using some kind of Map, but I wasn't sure of the best way to do so.
public class Symbol {
public static final int TREBLE_CLEF = 0;
public static final int BASS_CLEF = 1;
public static final int SEMIBREVE = 2;
// ...
public static final String S_TREBLE_CLEF = "treble-clef";
public static final String S_BASS_CLEF = "bass-clef";
public static final String S_SEMIBREVE = "semibreve";
// ...
public static int stringCodeToIntCode(String strCode) {
if (strCode == S_TREBLE_CLEF) {
return TREBLE_CLEF;
} else if (strCode == S_BASS_CLEF) {
return BASS_CLEF;
} else if (strCode == S_SEMIBREVE) {
return SEMIBREVE;
} //...
else {
return -1;
}
}
}
I think you are looking for Enum where you can have String constant and its value.
Example:
public enum YourEnumClass{
STRING_CONST (5),
STRING_CONST2 (7),
.....
//constructor
//getValue() method
}
read linked tutorial for more details.
enum StringToInt{
TREBLE_CLEF(0),
......
}
Enum is the way to go.
Another example:
public enum Color {
WHITE(21), BLACK(22), RED(23), YELLOW(24), BLUE(25);
private int code;
private Color(int c) {
code = c;
}
public int getCode() {
return code;
}
how about a hashmap
HashMap<String,Integer> hm=new HashMap<String,Integer();
hm.put("treble-clef",0);
//rest
and get it by using this
int value=hm.get("treble-clef");

Sort a vector of custom objects

How can I sort a vector of my custom object and choose which property to sort by?
I did see this question & answer but I'm not too sure what its sorting it based on. Code example would be prefered to "methodology".
Sort a Vector of custom objects
public class ItemLocation {
String icon;
String title;
String message;
String subtext;
String deviceId;
double latCoords;
double lngCoords;
int expiary;
int id;
double proximity;
String locSeen;
}
Below is a example that will allow you to sort by a specified field of ItemLocation:
public void sort(final String field, List<ItemLocation> itemLocationList) {
Collections.sort(itemLocationList, new Comparator<ItemLocation>() {
#Override
public int compare(ItemLocation o1, ItemLocation o2) {
if(field.equals("icon")) {
return o1.icon.compareTo(o2.icon);
} if(field.equals("title")) {
return o1.title.compareTo(o2.title);
} else if(field.equals("message")) {
return o1.message.compareTo(o2.message);
}
.
. fill in the rest of the fields...
.
else if(field.equals("locSeen")) {
return o1.locSeen.compareTo(o2.locSeen);
}
}
});
}
See the JavaDocs for java.util.Comparable and java.util.Comparator.
A class that implements Comparable can be compared against other instances of that class. This is useful to implement a natural search order. To allow ordering other than the class's natural order you would need to implement a Comparator. A Comparator is a separate object that is capable of comparing two other objects using whatever criteria it wants.
In your case you'd probably want to implement a Comparator for each of the different properties that you want to order by, or one that can be configured.
Comparable and Comparator both use the same idea to determine ordering: A method returns less than 0, 0, or greater than 0 to inform the caller which of the 2 objects is ordered first. In the case of Comparable the first object is this.
This one works:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* ComparableDemo
* #author Michael
* #since 2/24/11
*/
public class ComparableDemo
{
public static void main(String[] args)
{
List<ItemLocation> itemLocations = new ArrayList<ItemLocation>();
for (String arg : args)
{
itemLocations.add(new ItemLocation(arg));
}
System.out.println("before sort: " + itemLocations);
Comparator<ItemLocation> comparator = new ItemLocationComparator();
Collections.sort(itemLocations, comparator);
System.out.println("after sort: " + itemLocations);
}
}
class ItemLocation
{
String icon;
String title;
String message;
String subtext;
String deviceId;
double latCoords;
double lngCoords;
int expiary;
int id;
double proximity;
String locSeen;
ItemLocation(String message)
{
this("", "", message, "", "", 0.0, 0.0, 0, 0, 0.0, "");
}
ItemLocation(String icon, String title, String message, String subtext, String deviceId, double latCoords, double lngCoords, int expiary, int id, double proximity, String locSeen)
{
this.icon = icon;
this.title = title;
this.message = message;
this.subtext = subtext;
this.deviceId = deviceId;
this.latCoords = latCoords;
this.lngCoords = lngCoords;
this.expiary = expiary;
this.id = id;
this.proximity = proximity;
this.locSeen = locSeen;
}
#Override
public String toString()
{
final StringBuilder sb = new StringBuilder();
sb.append("ItemLocation");
sb.append("{message='").append(message).append('\'');
sb.append('}');
return sb.toString();
}
}
class ItemLocationComparator implements Comparator<ItemLocation>
{
public int compare(ItemLocation o1, ItemLocation o2)
{
return o1.message.compareTo(o2.message);
}
}
Here's the output:
C:\JDKs\jdk1.6.0_21\bin\java -Didea.launcher.port=7534 "-Didea.launcher.bin.path=C:\Program Files\JetBrains\IntelliJ IDEA 10.0.2\bin" -Dfile.encoding=windows-1252 com.intellij.rt.execution.application.AppMain ComparableDemo zeb meme apple
before sort: [ItemLocation{message='zeb'}, ItemLocation{message='meme'}, ItemLocation{message='apple'}]
after sort: [ItemLocation{message='apple'}, ItemLocation{message='meme'}, ItemLocation{message='zeb'}]
Process finished with exit code 0
Let's say we have a class with an int and a string. I can define how one object of that class may be compared against other.
I could choose any criteria. For instance, I may decide to sort based on the int. If I happen to have two int's with the same value, I may decide the string as an additional criteria, something like this:
// this class *knows* how to "compare" against him self
class CustomObject implements Comparable<CustomObject> {
String aString;
int aInt;
...
public int compareTo(CustomObject two ) {
int diff = this.aInt - two.aInt;//<-- compare ints
if( diff != 0 ) { // they have different int
return diff;
}
return this.aString.compareTo( two.aString );//<-- compare strings...
}
...
}
Here's a complete running demo ...
import java.util.*;
class SortDemo {
public static void main( String ... args ) {
// create a bunch and sort them
List<CustomObject> list = Arrays.asList(
new CustomObject(3, "Blah"),
new CustomObject(30, "Bar"),
new CustomObject(1, "Zzz"),
new CustomObject(1, "Aaa")
);
System.out.println( "before: "+ list );
Collections.sort( list );
System.out.println( "after : "+ list );
}
}
// this class *knows* how to "compare" against him self
class CustomObject implements Comparable<CustomObject> {
String aString;
int aInt;
CustomObject( int i, String s ) {
aInt = i;
aString = s;
}
// comparable interface lets you
// specify "HOW" to compare two
// custom objects
public int compareTo(CustomObject two ) {
// I migth compare them using the int first
// and if they're the same, use the string...
int diff = this.aInt - two.aInt;
if( diff != 0 ) { // they have different int
return diff;
}
// else let the strings compare them selves
return this.aString.compareTo( two.aString );
}
public String toString(){
return "CustomObject[aInt="+aInt+", aString="+aString+"]";
}
}
Here's the output:
before: [CustomObject[aInt=3, aString=Blah], CustomObject[aInt=30, aString=Bar], CustomObject[aInt=1, aString=Zzz], CustomObject[aInt=1, aString=Aaa]]
after : [CustomObject[aInt=1, aString=Aaa], CustomObject[aInt=1, aString=Zzz], CustomObject[aInt=3, aString=Blah], CustomObject[aInt=30, aString=Bar]]
I hope that's clear enough
You can also pass a custom comparator. Let me know if you need a sample of that.

Sorting not a standard LinkedList

I have a LinkedList<Individual> where Individual is a class that has a field processorTime.
It is needed to sort this LinkedList (descending order) basing on a function estimate(processorTime) which returns integers.
Please, tell me how can I do this?
Check this guide here:
http://leepoint.net/notes-java/data/collections/comparators.html
Quotations from the site:
The java.util.Comparator interface can be used to create objects to pass to sort methods or
sorting data structures. A Comparator must define a compare function which takes two
Objects and returns a -1, 0, or 1
Pasted code:
// File: arrays/filelist/Filelistsort.java
// Purpose: List contents of user home directory.
// Demonstrates use of Comparators to sort the
// same array by two different criteria.
// Author: Fred Swartz 2006-Aug-23 Public domain.
import java.util.Arrays;
import java.util.Comparator;
import java.io.*;
public class Filelistsort {
//======================================================= main
public static void main(String[] args) {
//... Create comparators for sorting.
Comparator<File> byDirThenAlpha = new DirAlphaComparator();
Comparator<File> byNameLength = new NameLengthComparator();
//... Create a File object for user directory.
File dir = new File(System.getProperty("user.home"));
File[] children = dir.listFiles();
System.out.println("Files by directory, then alphabetical");
Arrays.sort(children, byDirThenAlpha);
printFileNames(children);
System.out.println("Files by length of name (long first)");
Arrays.sort(children, byNameLength);
printFileNames(children);
}
//============================================= printFileNames
private static void printFileNames(File[] fa){
for (File oneEntry : fa) {
System.out.println(" " + oneEntry.getName());
}
}
}
////////////////////////////////////////////////// DirAlphaComparator
// To sort directories before files, then alphabetically.
class DirAlphaComparator implements Comparator<File> {
// Comparator interface requires defining compare method.
public int compare(File filea, File fileb) {
//... Sort directories before files,
// otherwise alphabetical ignoring case.
if (filea.isDirectory() && !fileb.isDirectory()) {
return -1;
} else if (!filea.isDirectory() && fileb.isDirectory()) {
return 1;
} else {
return filea.getName().compareToIgnoreCase(fileb.getName());
}
}
}
////////////////////////////////////////////////// NameLengthComparator
// To sort by length of file/directory name (longest first).
class NameLengthComparator implements Comparator<File> {
// Comparator interface requires defining compare method.
public int compare(File filea, File fileb) {
int comp = fileb.getName().length() - filea.getName().length();
if (comp != 0) {
//... If different lengths, we're done.
return comp;
} else {
//... If equal lengths, sort alphabetically.
return filea.getName().compareToIgnoreCase(fileb.getName());
}
}
}
Collections.sort(linkedList, new Comparator<Individual>() {
int compare(Individual i1, Individual i2) {
...
}
});
Do you mean the LinkedList is not standard, or the sort order based on processor time is not standard?
If the latter, then all you need to do is use Collections.sort(list,comparator) and provide an appropriate implementation of Comparator<NodeType> for your list. See also "implementing compareTo()" which gives some good related guidance.
Post the code for your node and the desired output, and we can give you more specific direction.
Collections.sort(list,new Comparator<Individual>() {
#Override
public int compare(final Individual i1, final Individual i2) {
return i1.processorTime - i2.processorTime;
}
#Override
public boolean equals(Object foo) {
return false; // doesn't matter, but false is better
}
});

Categories