I am having this issue where I have a PiorityBlockingQueue to sort the items in it. The are several options the user can sort the items being added into the queue.
The one I'm stuck at is trying to order the queue by the most occurences of an Item.
The choice of the comparison is determined in the constructor of MyQueue. But the counts of (eg. Low, Medium, High) isnt determined until later. When it is determined, I wanted to call the update(String lst) method from ItemComparator to update the hashmap so that the sorting is correct.
So my issue is I can't call that method. I know I'm missing something but I can't figure it out. Any help? Maybe there a better design than what I doing now?
public class ItemComparator implements Comparator<Item>
{
public void update(String lst){
test = lst;
}
public int compare(Item o1, Item o2) {
HashMap<String,Integer> priority = new HashMap<>();
priority.put("LOW", 1);
priority.put("MEDIUM", 2);
priority.put("HIGH", 3);
if (priority.get(o1.getPriority()) > priority.get(o2.getPriority())) {
return -1;
}
if (priority.get(o1.getPriority()) < priority.get(o2.getPriority())) {
return 1;
}
return 0;
}
}
This statement wont work from this class comparator.update(aString);
public class MyQueue implements AQueue{
private Comparator<Ticket> comparator;
private PriorityBlockingQueue<Ticket> listOfTickets;
private String policy;
BlockingQImpl(String processingPolicy) throws InvalidDataException {
setPolicy(processingPolicy.toUpperCase());
setComparator(policy);
}
private void setComparator(String policy) throws InvalidDataException {
if (policy.equals("THIS")) {
comparator = new ItemComparator(countString);
}
listOfTickets = new PriorityBlockingQueue<>(10, comparator);
}
public void addList(int id) {
ticks.add(id)
comparator.update(aString);
}
}
I think your problem is the compilation error at comparator.update(aString); right?
It is because you have declared comparator as Comparator<Ticket>, that means, you are "seeing" it as a Comparator, and in a Comparator, there is no update() method.
You should declare it as ItemComparator
i.e.
private ItemComparator comparator;
Related
This question already has answers here:
How to use Comparator in Java to sort
(16 answers)
Closed 5 years ago.
I also have an ArrayList items. I have classes derived from Media. Given the code below, how would I sort the arraylist by duration? e.g.
Collections.sort(myMedia, ?);
Here is the class
import java.util.Comparator;
public abstract class Media implements Comparable<Media>{
private int duration;
private String title;
private String imageFileName;
private static String imageFileDirectory = "src/resources/";
public Media(String name, int seconds) {
this.title = name;
this.duration = seconds;
this.imageFileName = "";
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getDuration() {
return duration;
}
public void setDuration(int d) {
this.duration = d;
}
public String getImageFileName() {
return imageFileName;
}
public void setImageFileName(String imageFileName) {
this.imageFileName = imageFileName;
}
public static String getImageFileDirectory() {
return imageFileDirectory;
}
public static void setImageFileDirectory(String imageFileDirectory) {
Media.imageFileDirectory = imageFileDirectory;
}
#Override
public String toString() {
return this.getTitle()
+ ", Duration: " + this.getDuration() + "s, " +
"Cost: " + costInPence() + "p";
}
public abstract int costInPence();
#Override
public int compareTo(Media o) {
return this.getTitle().compareTo(o.getTitle());
}
public static class DurationComparator implements Comparator<Media>{
public int compare(Media m1, Media m2) {
return m2.getDuration() - m1.getDuration();
}
}
public static class CostComparator implements Comparator<Media>{
public int compare(Media m1, Media m2) {
return m2.costInPence() - m1.costInPence();
}
}
}
The Collections#sort method has two variants.
The first variant (documentation) only accepts a collection that is to be sorted. It will sort the elements of the collection by their natural order. Therefore the elements must implement the interface Comparable which yields a compareTo method. Your Media objects already implement this interface with a meaningful natural order, namely sorting by their titles:
public abstract class Media implements Comparable<Media> {
#Override
public int compareTo(Media o) {
return this.getTitle().compareTo(o.getTitle());
}
}
The other variant (documentation) accepts a collection and a Comparator object. It will then sort the elements based on the order defined by the Comparator. You can define Comparator on various ways, since Java 8 it became pretty compact. But first let us take a look at the Comparator you have already defined, it sorts by duration:
public static class DurationComparator implements Comparator<Media> {
public int compare(Media m1, Media m2) {
return m2.getDuration() - m1.getDuration();
}
}
So if you want to sort by titles you should use the first variant. If you want to sort by duration you need to create a new instance of DurationComparator and use the second variant, alternatively use the compact Java 8 statements. The same holds for your CostComparator:
// Sort by title
Collections.sort(myMedia);
// Sort by duration
Collections.sort(myMedia, new DurationComparator<>());
// Sort by duration with Java 8
Collections.sort(myMedia, Comparator.comparingInt(Media::getDuration));
// Sort by cost
Collections.sort(myMedia, new CostComparator<>());
// Sort by cost with Java 8
Collections.sort(myMedia, Comparator.comparingInt(Media::costInPence));
The Comparator#comparing (documentation) method creates a Comparator object that sorts the given elements based on the given keys. The method reference points to a method that yields the keys.
As the methods return int you may choose the method Comparator#comparing (documentation) instead, it is slightly faster since int doesn't need to be boxed into Integer then.
Note that since Java 8 Lists itself provide a sort method too (documentation). So you don't need to call Collections anymore:
myMedia.sort(Comparator.comparingInt(Media::getDuration));
Also note that Comparator now provides some useful methods (documentation), for example to first sort by one key and if keys are equal then sort by a second key:
myMedia.sort(Comparator.comparingInt(Media::getDuration)
.thenComparing(Media::costInPence));
This is a bit embarrassing. I have a compareTo function that I intend to use on a JButton, so when the user presses it they can see which is the highest ranked object. I already have a Listener class for the JButton but I don't know how to make the Listener use the compareTo function because it needs two parameters.
This is my compareTo function:
public int compareTo(Film film1, Film film2) {
if (film1.getFinalScore() < film2.getFinalScore()) return -1;
if (film1.getFinalScore() > film2.getFinalScore()) return 1;
return 0;
}
And this is the actionPerformed function in the Listener class:
#Override
public void actionPerformed(ActionEvent e) {
this.cm.compareTo(null, null);
}
The Auto-correct suggested to put the parameters to null to make it work, but it's obviously never as simple as the Auto-Correct suggests.
So, how can I make the Listener perform the compareTo function using all of my objects to list them from highest to lowest?
Thanks in advance!
As you need to compare 2 Films together you can do that in Film Class by implementing Comparable<Film> then implementing the compareTo method in the class.
After That , Hold your films in any collection as ArrayList then simply call Collections.max(films) to get the max film object in the list.
Here is the a Film class for demonstration:
public class Film implements Comparable<Film>{
int finalScore ;
public Film(int finalScore){
this.finalScore = finalScore;
}
public int getFinalScore(){
return this.finalScore;
}
#Override
public int compareTo(Film film2) {
if (this.getFinalScore() < film2.getFinalScore()) return -1;
if (this.getFinalScore() > film2.getFinalScore()) return 1;
return 0;
}
}
And this is the main :
public static void main(String[] args) {
ArrayList<Film> films = new ArrayList<>();
films.add(new Film(100));
films.add(new Film(400));
films.add(new Film(200));
films.add(new Film(300));
System.out.println(Collections.max(films).getFinalScore());//prints 400
}
So your actionPerformed will be like this
#Override
public void actionPerformed(ActionEvent e) {
Film maxFilm = Collections.max(films);
//then use maxFilm object to do anything you need
}
I got a class used in an Android app, which is declared like this:
public static class MyData implements Comparable<MyData>
{
public MyEnum myEnum;
#Override
public int compareTo(MyData another)
{
if(this.myEnum.equals(MyEnum.Value1))
{
return 1;
}
if(another.myEnum.equals(MyEnum.Value1))
{
return -1;
}
if(this.myEnum.equals(MyEnum.Value2))
{
return 1;
}
if(another.myEnum.equals(MyEnum.Value2))
{
return -1;
}
return 0;
}
}
I defined a list: List<MyData> myList = new LinkedList<MyData>();
After adding items to the list I call: Collections.sort(myList)
The problem is that when I debug, I see the compareTo method being called after the sort method is invoked, however it doesn't enter the first if even that it should. I even put the Boolean expression in Eclipse in the "Expressions" view and it returned true, but the code simply jumps to the return 0; and the list is not being sorted like I want to.
Why is that?
Eventually I changed that enum class member to an int member which was initialized with the ordinal value inside the Enum.
Then the compareTo method was changed like this:
#Override
public int compareTo(MyData another)
{
Integer myVal = this.intVal;
Integer otherVal = another.intVal;
return myVal.compareTo(otherVal);
}
I'll get right to it.
So I have code that gets a Null Pointer Exception. I've tried looking up what causes it and how to fix it, but that's why I'm confused with this particular code. It was working just fine earlier today and now its throwing the exception. Any help? I'm probably just overlooking something silly but it's quite frustrating. Code follows:
import java.util.*;
import java.io.*;
public class ShopMain<T> {
List<T> stock;
public void Shop() { stock = new LinkedList<T>(); }
public T buy() { return stock.remove(0); }
void sell(T item) { stock.add(item); }
void buy(int n, Collection<? super T>items) {
for (T e : stock.subList(0, n)) {
items.add(e);
}
for (int i=0; i<n; ++i) stock.remove(0);
}
void sell(Collection<? extends T> items) {
for (T e : items) {
stock.add(e);
}
}
public static void main (String[] args) {
ShopMain<Marker> paintballShop = new ShopMain<Marker>();
Console console = System.console();
System.out.println("1 - Test Suite");
String input = console.readLine("Please select the corresponding number to your choice.\n");
if(input.equals("1")){
Stack<Marker> stack = new Stack<Marker>();
Set<Marker> hashset = new HashSet<Marker>();
System.out.println("Test Suite : Tests List, Stack, HashSet");
paintballShop.sell(new Geo3());
paintballShop.sell(new Ego11());
paintballShop.buy();
paintballShop.buy(2, stack); //Stack use
paintballShop.sell(stack); //Stack use
paintballShop.buy(3, hashset); //HashSet
paintballShop.sell(hashset); //HashSet
System.out.println("Tests Complete");
}
}
}
Exception error occurring at runtime:
Exception in thread "main" java.lang.NullPointerException
at ShopMain.sell(ShopMain.java:14)
at ShopMain.main(ShopMain.java:39)
These last bits are just class 'placeholders' for the objects and their parent class.
public class Marker{}
public class Geo3 extends Marker{}
public class Ego11 extends Marker{}
Thanks again for any help.
That's because your List List<T> stock; is still uninitialized. You need to initialize it for you to be able to add, remove elements to/from it. By default, its null and thus, when you try to call a method on it, you get the NullPointerException.
This happens because you don't have a constructor at all. Shop() is not the constructor of your class. A constructor has the same name as the class, and thus you need to have your constructor like this
public ShopMain() { stock = new LinkedList<T>(); }
Incase, Shop() is a valid method, then you need to call this method so that your list is initialized and only then call the other methods.
paintballShop.Shop(); // Call this method to init your list.
change to constructor..
public ShopMain() { stock = new LinkedList<T>(); }
You probably need to change:
public void Shop() { stock = new LinkedList<T>(); }
//doesn't look a method name, may be this is what you missed
to
public ShopMain() { stock = new LinkedList<T>(); }
You don't have a constructor for ShopMain that initializes your List.
Add this:
ShopMain() {
stock<T> = new ArrayList<T>();
}
Basically it comes do to the fact that stock is never initialised. I imagine that the class use to be called Shop
You could change...
public class ShopMain<T> {
List<T> stock;
public void Shop() {
stock = new LinkedList<T>();
}
To...
public class ShopMain<T> {
List<T> stock;
public ShopMain() {
stock = new LinkedList<T>();
}
Which will initialise the List when the class is constructored...
Is it possible to have multiple iterators in a single collection and have each keep track independently? This is assuming no deletes or inserts after the iterators were assigned.
Yes.
Sometimes it's really annoying that answers have to be 30 characters.
Yes, it is possible. That's one reason they are iterators, and not simply methods of the collection.
For example List iterators (defined in AbstractList) hold an int to the current index (for the iterator). If you create multiple iterators and call next() a different number of times, each of them will have its int cursor with a different value.
Yes and no. That depend of the implementation of the interface Iterable<T>.
Usually it should return new instance of a class that implement Iterable interface, the class AbstractList implements this like that:
public Iterator<E> iterator() {
return new Itr(); //Where Itr is an internal private class that implement Itrable<T>
}
If you are using standard Java classes You may expect that this is done this way.
Otherwise You can do a simple test by calling iterator() form the object and then run over first and after that second one, if they are depend the second should not produce any result. But this is very unlikely possible.
You could do something like this:
import java.util.ArrayList;
import java.util.Iterator;
public class Miterate {
abstract class IteratorCaster<E> implements Iterable<E>, Iterator<E> {
int mIteratorIndex = 0;
public boolean hasNext() {
return mStorage.size() > mIteratorIndex;
}
public void remove() {
}
public Iterator<E> iterator() {
return this;
}
}
class FloatCast extends IteratorCaster<Float> {
public Float next() {
Float tFloat = Float.parseFloat((String)mStorage.get(mIteratorIndex));
mIteratorIndex ++;
return tFloat;
}
}
class StringCast extends IteratorCaster<String> {
public String next() {
String tString = (String)mStorage.get(mIteratorIndex);
mIteratorIndex ++;
return tString;
}
}
class IntegerCast extends IteratorCaster<Integer> {
public Integer next() {
Integer tInteger = Integer.parseInt((String)mStorage.get(mIteratorIndex));
mIteratorIndex ++;
return tInteger;
}
}
ArrayList<Object> mStorage;
StringCast mSC;
IntegerCast mIC;
FloatCast mFC;
Miterate() {
mStorage = new ArrayList<Object>();
mSC = new StringCast();
mIC = new IntegerCast();
mFC = new FloatCast();
mStorage.add(new String("1"));
mStorage.add(new String("2"));
mStorage.add(new String("3"));
}
Iterable<String> getStringIterator() {
return mSC;
}
Iterable<Integer> getIntegerIterator() {
return mIC;
}
Iterable<Float> getFloatIterator() {
return mFC;
}
public static void main(String[] args) {
Miterate tMiterate = new Miterate();
for (String tString : tMiterate.getStringIterator()) {
System.out.println(tString);
}
for (Integer tInteger : tMiterate.getIntegerIterator()) {
System.out.println(tInteger);
}
for (Float tFloat : tMiterate.getFloatIterator()) {
System.out.println(tFloat);
}
}
}
With the concurrent collections you can have multiple iterators in different threads even if there inserts and deletes.