So the question is as follows
A unique id is assigned to each student entering the queue. The queue serves the students based on the following criteria (priority criteria):
The student having the highest Cumulative Grade Point Average (CGPA) is served first.
Any students having the same CGPA will be served by name in ascending case-sensitive alphabetical order.
Any students having the same CGPA and name will be served in ascending order of the id
My code
class Priorities{
public List<Students> getStudents(List<String> events) {
PriorityQueue<Students> pq = new PriorityQueue<Students>();
for ( String s : events) {
if ( s.contains("ENTER")) {
String [] arr = s.split(" ");
int id = Integer.parseInt(arr[3]);
String name = arr[1];
Double cgpa = Double.parseDouble(arr[2]);
pq.add(new Students(id, name, cgpa));
}
else
pq.poll();
}
List<Students> studentList = new ArrayList<Students>(pq);
return studentList;
}
}
class Students implements Comparable<Students>{
int id;
String name;
double cgpa;
public Students(int id, String name, double cgpa) {
this.id = id;
this.name = name;
this.cgpa = cgpa;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getCgpa() {
return cgpa;
}
public void setCgpa(double cgpa) {
this.cgpa = cgpa;
}
// -1 return left, 1 return right
public int compareTo(Students other) {
if ( this.equals(other))
return 0;
else if ( this.getCgpa() > other.getCgpa())
return -1;
else if ( this.getCgpa() < other.getCgpa())
return 1;
else if ( this.getCgpa() == other.getCgpa() && this.getName().compareTo(other.getName()) == 0)
return Integer.compare(this.getId(), other.getId());
else
return this.getName().compareTo(other.getName());
}
}
Sample input
12
ENTER John 3.75 50
ENTER Mark 3.8 24
ENTER Shafaet 3.7 35
SERVED
SERVED
ENTER Samiha 3.85 36
SERVED
ENTER Ashley 3.9 42
ENTER Maria 3.6 46
ENTER Anik 3.95 49
ENTER Dan 3.95 50
SERVED
Sample output
Dan
Ashley
Shafaet
Maria
I'm getting the following
Dan
Ashley
Maria
Shafaet
Edit: Using
List<Students> studentList = new ArrayList<Students>();
while(!pq.isEmpty())
{
studentList.add(pq.poll());
}
instead of List studentList = new ArrayList(pq); helps with copying the exact order of the PQ to the list.
The general structure of a comparator should be: compare a field; if the field values differ, return; if they are the same, proceed to the next field.
In this case, it could look something like:
int cmp;
cmp = Double.compare(other.getCgpa(), this.getCgpa());
if (cmp != 0) return cmp;
cmp = this.getName().compareTo(other.getName());
if (cmp != 0) return cmp;
cmp = Integer.compare(this.getId(), other.getId());
if (cmp != 0) return cmp;
return 0;
(The last if and return could be collapsed to just return cmp;; but I think it's easier to extend later if you do it as above, because you can then just insert another cmp/if.)
The issue is that PriorityQueue's ordering semantic are not guaranteed in its iterator (on top of that, note that PriorityQueue is not a List !)
Quoting from the java doc (emphasis mine) :
This class and its iterator implement all of the
optional methods of the Collection and
Iterator interfaces. The Iterator provided in method
iterator() is not guaranteed to traverse the elements of
the priority queue in any particular order. If you need ordered
traversal, consider using Arrays.sort(pq.toArray()).
Which means you will not get your comparator's ordering unless you use the queue semantics (e.g. add, poll, remove, offer... and the likes).
And looking at implementations, calling new ArrayList<Students>(pq); (or PriorityQueue#toString() for that matter) is implemented using an iterator, so it does not respect the priority.
The takeaway here :
Using PriorityQueue is OK in the case of queue semantics only, not iteration / random access
Combining both List and "live" sorting is not provided by a standard Java class that I know of (see also). (You can sort a list using a comparator, but there is no list that is sorted each time you add an element). There are such collections, though, using Set semantics, see TreeSet, you'll find them on the linked answers. Be warned that Set semantics are different (they maintain unicity of their elements, the meaning of unicity being somewhat tricky to get. For example, HashSet unicity is defined by hashCode/equals, but TreeSet's is defined by a comparator's).
That being said, Andy's implementation of the comparator is by far more readable (and avoids repetitions).
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I'm looking for some tip on how to do a percentage thing for my game I want all flowers in a range of 1-98 and white/black flowers 99-100 to make it more rarerity thanks for the help :)
public enum FlowerSuit {
WHITE_FLOWERS("white", ":white:", "470419377456414720", 1),
YELLOW_FLOWERS("yellow", ":yellow:", "470419561267855360", 1 ),
RED_FLOWERS("red", ":red:", "470419583250202644", 1),
RAINBOW_FLOWERS("rainbow", ":rainbow:", "470419602841665536", 1),
PASTEL_FLOWERS("pastel", ":pastel:", "470419629450199040", 1),
ORANGE_FLOWERS("orange", ":orange:", "470419647900942366", 1),
BLUE_FLOWERS("blue", ":blue:", "470419688753594368", 1),
BLACK_FLOWERS("black", ":black:", "470419706751352842", 1);
private final String displayName;
private final String emoticon;
private int value;
private final String id;
FlowerSuit(String displayName, String emoticon, String id, int value ) {
this.displayName = displayName;
this.emoticon = emoticon;
this.value = value;
this.id = id;
}
public String getDisplayName() {
return displayName;
}
public String getEmoticon() {
return emoticon;
}
public String getId() {
return id;
}
public int getValue() {
// TODO Auto-generated method stub
return value;
}
}
This is how I'd do it, but it can probably be improved, for starters by using Java 8 streams etc.
public enum FlowerSuit {
WHITE_FLOWERS("white", ":white:", "470419377456414720", 1,3),
YELLOW_FLOWERS("yellow", ":yellow:", "470419561267855360", 1,2),
RED_FLOWERS("red", ":red:", "470419583250202644", 1,2),
RAINBOW_FLOWERS("rainbow", ":rainbow:", "470419602841665536", 1,2),
PASTEL_FLOWERS("pastel", ":pastel:", "470419629450199040", 1,2),
ORANGE_FLOWERS("orange", ":orange:", "470419647900942366", 1,2),
BLUE_FLOWERS("blue", ":blue:", "470419688753594368", 1,2),
BLACK_FLOWERS("black", ":black:", "470419706751352842", 1,1);
private static Random random = new Random();
private final String displayName;
private final String emoticon;
private int value;
private final String id;
private final int freq;
private FlowerSuit(String displayName, String emoticon, String id, int value, int freq ) {
this.displayName = displayName;
this.emoticon = emoticon;
this.value = value;
this.id = id;
this.freq = freq;
}
public String getDisplayName() {return displayName;}
public String getEmoticon() {return emoticon;}
public String getId() {return id;}
public int getValue() {return value;}
/**
* Choose a flower
* white has a 3 in 16 (about a 5:1) chance of being picked
* Black has a 1 in 16 chance, everything else 2/16
* #return
*/
public static FlowerSuit pick() {
//first sum all the chances (currently it's 16)
int sum = 0;
for (FlowerSuit f:FlowerSuit.values()) sum+= f.freq;
//now choose a random number
int r = FlowerSuit.random.nextInt(sum) + 1;
//now find out which flower to pick
sum = 0;
for (FlowerSuit f:FlowerSuit.values()) {
sum += f.freq;
if (r<=sum) return f;
}
//code will never get here
return FlowerSuit.WHITE_FLOWERS;
}
public static void main(final String[] args) throws Exception {
//Test it
Map<FlowerSuit,Integer>count = new HashMap<FlowerSuit,Integer>();
for (int a=0;a<1000000;a++) {
FlowerSuit f = FlowerSuit.pick();
Integer i = (count.get(f)!=null)?count.get(f):new Integer(0);
i = new Integer(i+1);
count.put(f,i);
}
int sum = 0;
for (Map.Entry<FlowerSuit,Integer>e:count.entrySet()) sum+=e.getValue();
float f = Float.valueOf(sum);
for (Map.Entry<FlowerSuit,Integer>e:count.entrySet()) {
System.out.println(e.getKey() + " was chosen " + ((e.getValue() / f) * 100f) + "% of the time");
}
}
}
gives
BLUE_FLOWERS was chosen 12.4986% of the time
PASTEL_FLOWERS was chosen 12.4707% of the time
WHITE_FLOWERS was chosen 18.7365% of the time
BLACK_FLOWERS was chosen 6.2632003% of the time
ORANGE_FLOWERS was chosen 12.4986% of the time
RED_FLOWERS was chosen 12.5241995% of the time
YELLOW_FLOWERS was chosen 12.501401% of the time
RAINBOW_FLOWERS was chosen 12.5068% of the time
You can use a TreeMap to map all of the integers from 0 to 99 to a particular FlowerSuit. Take advantage of the floorEntry method to choose a FlowerSuit for each number. It might look something like this.
public class FlowerChooser {
private static final NavigableMap<Integer, FlowerSuit> FLOWER_SUITS;
private static final Random RANDOMS = new Random();
public FlowerChooser() {
FLOWER_SUITS = new TreeMap<>();
FLOWER_SUITS.put(0, FlowerSuit.RED_FLOWERS);
FLOWER_SUITS.put(14, FlowerSuit.ORANGE_FLOWERS);
FLOWER_SUITS.put(28, FlowerSuit.YELLOW_FLOWERS);
FLOWER_SUITS.put(42, FlowerSuit.GREEN_FLOWERS);
FLOWER_SUITS.put(56, FlowerSuit.BLUE_FLOWERS);
FLOWER_SUITS.put(70, FlowerSuit.INDIGO_FLOWERS);
FLOWER_SUITS.put(84, FlowerSuit.VIOLET_FLOWERS);
FLOWER_SUITS.put(98, FlowerSuit.WHITE_FLOWERS);
FLOWER_SUITS.put(99, FlowerSuit.BLACK_FLOWERS);
}
public FlowerSuit randomFlowerSuit() {
int index = RANDOMS.nextInt(100);
return FLOWER_SUITS.floorEntry(index).getValue();
}
}
Create just one object of this class, then whenever you want a FlowerSuit, call the randomFlowerSuit method.
The randomFlowerSuit method picks a random number from 0 to 99, then finds an appropriate entry in the map. The floorEntry method chooses an entry whose key is less than or equal to the chosen number. This means that numbers from 0 to 13 get mapped to red, 14 to 27 get mapped to orange, and so on. The only number that gets mapped to white is 98, and the only number that gets mapped to black is 99.
No matter what solution you implement, you want to include a frequency measure in your enum. As an example, you can do something like this:
public enum FlowerSuit {
WHITE_FLOWERS("white", ":white:", "470419377456414720", 1, 1),
YELLOW_FLOWERS("yellow", ":yellow:", "470419561267855360", 1, 20),
// More declarations here
// Add this variable
private final int frequency;
// Do just as you did before in the constructor, but with the frequency
FlowerSuit(String displayName, String emoticon, String id, int value, int frequency){
this.frequency = frequency;
// More assignments here
}
public int getFrequency(){
return frequency;
}
// More getters here
}
This addition is critical, and no matter what method you use to weight flower selection, you will want this addition to your FlowerSuit enum.
Now, we can explore a few different ways to perform this selection.
Note 1: I use ThreadLocalRandom for random numbers in a range, which is from java.util.concurrent.ThreadLocalRandom.
Note 2: For each of these, make a single instance of FlowerPicker, and use the pickFlower() method to pick the next flower. This avoid running costly setup code over and over.
Method 1: Bag of Flowers
This method is probably the easiest to implement. It entails creating a list of enums where each is represented frequency times, and then selecting a random entry from this list. It is similar to throwing a bunch of flowers in a bag, shaking it, and then reaching your hand in and grabbing the first flower you touch. Here's the implementation:
public class FlowerPicker(){
private ArrayList<FlowerSuit> bag;
public FlowerPicker(){
// Get all possible FlowerSuits
FlowerSuit[] options = FlowerSuit.values();
// You can use an array here or an array list with a defined length if you know the total of the frequencies
bag = new ArrayList<FlowerSuit>();
// Add each flower from options frequency times
for (FlowerSuit flower : options)
for (int i=0; i<flower.getFrequency(); i++)
bag.add(flower);
}
public FlowerBag pickFlower(){
// Now, select a random flower from this list
int randomIndex = ThreadLocalRandom.current().nextInt(0, bag.size());
return bag.get(randomIndex);
}
}
This method has the advantage of being simple enough to understand very easily. However, it can be inefficient if your frequencies are extremely specific (like if you want a rainbow flower to be returned 499,999,999 times out of 1,000,000,000). Let's move on to the next method.
Note 1: You could make this better by reducing the fractions representing the frequency of being chosen, but I'll leave this to you.
Note 2: You could also make this slightly better by storing identification numbers, not FlowerSuit objects in the bag list.
Method 2: Navigable Map
This method is a little bit more difficult. It uses a [NavigableMap][1], which is an implementation of [TreeMap][2]. This method is fairly similar to the Bag of Flowers method, but it is a little bit more efficient. Put simply, it uses the TreeMap to give each FlowerSuit a range of numbers that can be selected to return that FlowerSuit. Here's a full example:
public class FlowerPicker(){
private NavigableMap<Double, FlowerSuit> map;
public FlowerPicker(){
// Get all possible FlowerSuits
FlowerSuit[] options = FlowerSuit.values();
map = new TreeMap<Double, FlowerSuit>();
int runningTotal = 0;
// Add each flower with the proper range
for (FlowerSuit flower : options){
runningTotal += flower.getFrequency();
map.put(runningTotal, flower);
}
}
public FlowerBag pickFlower(){
// Now, select a random number and get the flower with this number in its range
int randomRange = ThreadLocalRandom.current().nextInt(0, bag.size());
return map.higherEntry(randomRange).getValue();
}
}
This is a solid method, and it scales well for very specific frequencies. If you have a bunch of different types of flowers, it will be slightly worse, but this method is still a good option at large scales. There's one more option though.
Method 3: Enumerated Distribution
This method is really nice because you barely have to do anything. However, it uses [EnumeratedDistribution][3] from Apache Commons. Enumerated Distribution requires a list of pairs of objects and weights. Anyway, lets jump into it:
public class FlowerPicker(){
private EnumeratedDistribution distribution;
public FlowerPicker(){
// Get all possible FlowerSuits
FlowerSuit[] options = FlowerSuit.values();
List<Pair<FlowerSuit, Double>> weights = new List<Pair<FlowerSuit, Double>>();
// Add each flower and weight to the list
for (FlowerSuit flower : options){
weights.add(new Pair(flower, flower.getFrequency()));
// Construct the actual distribution
distribution = new EnumeratedDistribution(weights);
}
public FlowerBag pickFlower(){
// Now, sample the distribution
return distribution.sample();
}
}
This is my favorite method, simply because so much of it is done for you. Many problems like this have been solved, so why not use solutions that always exist? However, there is some value to writing the solution yourself.
In conclusion, each of these methods are perfectly fine to use at your scale, but I would recommend the second or third method.
I have a TreeMap containing a mapping of StockItem values:
private final Map<StockItem, Integer> list;
I am using a method to look up values within this map by generating a key which returns a type of StockItem.
Here is the method:
public static StockItem makeKey(String name, double price, int quantityStock){
return new StockItem(name,price,quantityStock);
}
The code works fine and lookups work well, my question is how exactly is it possible for this to happen? The makeKey method returns a completely new object which contains the exact same data that may be contained in a list. Does it go through each iteration then call .equals to compare each object?
Here is the StockItem class:
public class StockItem implements Comparable<StockItem> {
private final String name;
private int quantity;
private double price;
private int reserveItems = 0;
public StockItem(String name, double price) {
this.name = name;
this.price = price;
quantity = 0;
}
public StockItem(String name, double price, int quantityStock) {
this.name = name;
this.price = price;
quantity = quantityStock;
}
public void reserveItem(int amountReserved){
this.reserveItems = amountReserved + this.reserveItems;
}
public void unReserveItem(int unreserve){
reserveItems = reserveItems - unreserve;
}
public int getReservedAmount(){
return reserveItems;
}
public String getName() {
return name;
}
public int quantityInStock() {
return quantity;
}
public double getPrice() {
return price;
}
public void adjustStock(int quantity) {
this.quantity = this.quantity + quantity - this.reserveItems;
}
public final void setPrice(double price) {
if (price > 0.0)
this.price = price;
}
public static StockItem MakeKey(String name, double price, int quantityStock){
return new StockItem(name,price,quantityStock);
}
#Override
public int compareTo(StockItem o) {
if (this == o){
return 0;
}
if (o != null){
return this.name.compareTo(o.getName());
}
throw new NullPointerException();
}
public String toString(){
return "Item Name: " + this.name + " Item Price: " + this.price;
}
}
A TreeMap without a Comparator such as in your example does its lookups based on whether its objects' compareTo methods deem the items as being equal:
a sorted map performs all key comparisons using its compareTo (or compare) method, so two keys that are deemed equal by this method are, from the standpoint of the sorted map, equal.
Since StockItem's compareTo returns true whenever the name values are equal, and since the "key" items contain the name value, the map lookup by key returns the corresponding item as the "key" object is considered equal to the whole object by the map.
The answer to your question of how it works and whether it iterates through each object can be determined from TreeMap's Javadocs:
A Red-Black tree based NavigableMap implementation.
[...]
This implementation provides guaranteed log(n) time cost for the containsKey, get, put and remove operations. Algorithms are adaptations of those in Cormen, Leiserson, and Rivest's Introduction to Algorithms.
As stated, the lookups are performed using a red–black tree. The details of how that works are outside the scope of what can be reasonably fit in this answer. However, the fact that the get method is defined to be log(n) time cost tells us that it's not iterating over all elements in the list, as an iteration over all elements would be a more expensive n time cost.
The aim of this method here is to bubble sort according to a person's ID
however in this area:
if (al.get(i).compareTo(al.get(i+1)) > 0 )
it states: cannot find symbol - method compareTo(java.lang.Object)
This is the class person (not very imp) / / / /
public class Person implements java.io.Serializable
{
String personID;
String name;
byte dayDOB;
byte monthDOB;
short yearDOB;
String telNum;
}
This is the sort method:
public static void sort(ArrayList al)
{
Person p;
String temp;
boolean flag = true;
System.out.println("Database will be sorted acc to ID ");
System.out.println();
while (flag = true)
{
flag = false;
for (int i=0;i<al.size()-1;i++)
{
p = (Person) al.get(i);
if (al.get(i).compareTo(al.get(i+1)) > 0 )
{
temp = al.get(i);
al.set(i,al.get(i+1) );
al.set(i+1, temp);
flag = true;
}
}
}
}
PS; I am a newbie when it comes to code and have been modifying this code for up to 7 hours already
Objects come with a built in compareTo() method, but it's best to override the default. See the java documentation for compareTo(). That should simplify your code quite a bit.
Your Person class will need to implement Comparable and include that in the class declaration. You can then write a compareTo() method something like this:
public int compareTo(Person b) {
return this.name.compareTo(b.getName());
}
A compareTo() method should return -1, 0, or 1. If you call a.compareTo(b) in your main class, compareTo() should return zero if the objects are sorted to the same place (i.e. equal), -1 if object a should be sorted before object b, or 1 if object a should be sorted after b.
You'll need to decide what constitutes the same person and how they should be sorted. Alphabetically based on name? Name and id? Whatever it is for your program.
i am looking for a way to check if an array contains more than 1 instances of the same object. I've been looking around but can't seem to find anything in the javadoc nor stackoverflow.
I am creating a monopoly board game (or in danish, matador) where the fee from landing on one of the fields differs depending on how many of that type of field the player owns.
I have a list in my player class in which i put all the fields that the player buys:
public List<OwnableField> ownsList = new ArrayList<>();
public void buy(OwnableField ownable) {
pay(ownable.getPrice());
ownsList.add(ownable);
}
And then i have this method in the specific field class, in which i am working on an if statement to set the fee:
public int fee;
public int feeCalc(int diceScore) {
if(this.getOwner().ownsList.(whatever checks for duplicate object in array)){
fee = 200 * diceScore;
} else {
fee = 100 * diceScore;
}
return fee;
}
If you have a proper equals and hash code defined then you can use sets to achive that
List list = ...
if(new HashSet(list).size().equals(list.size()){
//same size
} else {
//there was a duplicated element
}
If you want to check for one specific object only you could do it with:
final Object someObject = ...
List list = ...
int size = FluentIterable.from(list).filter(new Predicate<Object>() {
#Override
public boolean apply(Object input) {
return input == someObject;
}
}).size();
if(size > 1) {
//there is a duplicated element
}
Or, if you are looking for an instance of a class, then try:
List list = ...
int size = FluentIterable.from(list).filter(Predicates.instanceOf(YourClass.class)).size();
if(size > 1) {
//there is a duplicated element
}