First and Foremost, I must mention after reading lots of questions and tutorials and watching some videos, still the problem is not resolved.
I am an intermediate programmer in Java, and I have written some codes for comparing elements in a priority queue, in which elements are kept like [Comparable element, int priority]. Obviously, the higher priority would be popped.
the problem is:
I modified the code to have the first element with highest priority, and it does NOT work! I have narrowed it down that when comparing the first 2 elements, the compareTo method returns 0, which it should NOT, consequently the code fails!
this is the class that has the push of O(1) and Pop of O(n):
public class PriorityQueueU<T>
{
public class PriorityPair implements Comparable
{
public Comparable element;
public Comparable priority;
public PriorityPair(Comparable element, int priority){
this.element = element;
this.priority = priority;
}
public Comparable<T> getElemet(){
return this.element;
}
public Comparable<T> getPriority(){
return this.priority;
}
public int compareTo(Comparable a)
{
PriorityPair p2 = (PriorityPair)a;
return ((Comparable)priority).compareTo(p2.priority);
}
public String toString(){
String s1 = this.element.toString();
String s2 = this.priority.toString();
String res = "[ " + s1 + ", " + s2 + " ]" ;
return res;
}
public int compareTo(Object o)
{
// TODO Auto-generated method stub
return 0;
}
}
private LinkedList data;
public PriorityQueueU()
{
data = new LinkedList();
}
public void pushUnsorted(Comparable<T> o, int priority)
{
PriorityPair paired = new PriorityPair(o, priority);
data.addLast(paired);
}
public Comparable popUnsorted()
{
int index = 0;
for (int i = 0; i < this.data.size() - 1; i++)
{
if (((PriorityPair) this.data.get(i)).compareTo(this.data.get(i + 1)) < 0)
{
index = i + 1;
}
}
PriorityPair pp = (PriorityQueueU<T>.PriorityPair) this.data.get(index);
this.data.deleteIt(index);
return pp.getElemet();
}
public String toString(){
return this.data.toString();
}
}
}
and this is the code that would test the behavior:
PriorityQueueU<T> unSortedPQ = new PriorityQueueU<>();
unSortedPQ.pushUnsorted( (Comparable<T>) "a", 1000);
unSortedPQ.pushUnsorted((Comparable<T>) "b", 200);
unSortedPQ.pushUnsorted((Comparable<T>) "j", 900);
unSortedPQ.pushUnsorted((Comparable<T>) "r", 9);
unSortedPQ.pushUnsorted((Comparable<T>) "z", 6);
System.out.println("the UNsorted priority Q: ");
System.out.println(unSortedPQ);
System.out.println("*#------------------END OF PUSH-----------------#*");
System.out.println();
System.out.println("the priority Q: " + unSortedPQ);
System.out.println("popped item is: " + unSortedPQ.popUnsorted());
// System.out.println("top of the priority queue is: " + uPriorityQueueU.top());
System.out.println();
System.out.println("the UNsorted priority Q: ");
System.out.println(unSortedPQ);
System.out.println("*#------------------END OF POP-----------------#*");
System.out.println();
MANY thanks in advance.
P.S. bear in mind that maybe I was wrong and the problem was somewhere else!
current behavior: it pops j, which is the second highest element in the list. I already know that when popping, the element must be deleted as well from the priority queue, which is stored in a linked list. I made sure deletion in linked list is correctly working, but don't hesitate to ask for the code if necessary.
In order for compareTo to work, you should implement the method provided by the Comparable interface.
public interface Comparable<T> {
public int compareTo(T o);
}
As we see from the code above, Copmarable supports generics. If you do not specify what type of objects you want to compare (leave it as it is), it will default to Object, which it does (that's from your code):
public int compareTo(Object o)
{
// TODO Auto-generated method stub
return 0;
}
So you either use generics or write logic for compareTo(Object o).
Related
I need to sort my grocery inventory by name by using bubble sort.
Apparently, my code is not sorting the list by name.
BTW, the data stored inventory comes from a file input.
Here is my code.
public void sortInventoryByName() {
//TODO: use bubble sort and compareTo
int n = inventory.size();
GroceryItem temp;
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (inventory.get(j).compareTo(inventory.get(j + 1)) > 0) {
temp = inventory.get(i);
inventory.set(i, inventory.get(i + 1));
inventory.set(i + 1, temp);
}
}
}
}
Here is my compareTo method from my superclass (GroceryItem)
#Override
public int compareTo(Object o) {
if(getClass() != o.getClass()) {
throw new IllegalArgumentException();
}
else {
GroceryItem other = (GroceryItem) o;
return (this.name.compareTo(other.name));
}
}
Looks like you have some mismatch for comparing the right values.
There are two ways of implementing a bubble sort algorithm with two for loops.
Below made the first loop incremented barrier variable and second is decrementing index.
Thus with every iteration of the outer loop, the lowest value will be moved to the first place (like the smallest bubble will be moved first). The next iteration will skip this first element. And it will last till the list full list will be over.
Your example shows opposite behaviour -> with every iteration for the outer loop the highest element in a list is moved to the end.
It isn't so important how exactly do you want to iterate the inner for loop. The final sorted result is our aim.
Code snippet:
public void sortInventoryByName() {
int n = inventory.size();
for (int barrier = 0; barrier < n - 1; barrier++) {
for (int index = n - 2; index >= barrier; index--) {
if (inventory.get(index).compareTo(inventory.get(index + 1)) > 0) {
GroceryItem temp = inventory.get(index);
inventory.set(index, inventory.get(index + 1));
inventory.set(index + 1, temp);
}
}
}
}
Your implementation of compareTo() should work fine. So, inventory list should be sorted correctly.
A few notices according to your code:
you don't need to declare temp variable outside of loops. It is just a temporary variable for swapping two values. Inline declaration and usage will be enough.
would suggest adding more meaningful names for loop variables instead of just i and j. It increases code readability and understanding in the future
else block is redundant at compareTo()
#Override
public int compareTo(Object o) {
if (getClass() != o.getClass()) {
throw new IllegalArgumentException();
}
GroceryItem other = (GroceryItem) o;
return this.name.compareTo(other.name);
}
I filled in the missing parts of your code. You should read How do I ask a good question and also the link to How to create a Minimal, Reproducible Example.
The below code is the GroceryItem class which only contains a single member, i.e. name, which is the name of the grocery item. Since your question only deals with manipulating this member, I did not try to guess what other data the class needs.
Explanations after the code.
import java.util.ArrayList;
import java.util.List;
public class GroceryItem implements Comparable<GroceryItem> {
private String name;
public GroceryItem(String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override // java.lang.Comparable
public int compareTo(GroceryItem other) {
if (other == null) {
return 1;
}
else {
String otherName = other.getName();
if (name == null) {
if (otherName == null) {
return 0;
}
else {
return -1;
}
}
else {
if (otherName == null) {
return 1;
}
else {
return name.compareTo(otherName);
}
}
}
}
#Override // java.lang.Object
public boolean equals(Object other) {
boolean equal = false;
if (other instanceof GroceryItem) {
GroceryItem otherItem = (GroceryItem) other;
if (name == null) {
equal = otherItem.getName() == null;
}
else {
equal = name.equals(otherItem.getName());
}
}
return equal;
}
#Override // java.lang.Object
public int hashCode() {
return name == null ? 0 : name.hashCode();
}
#Override // java.lang.Object
public String toString() {
return name;
}
public static void main(String[] args) {
List<GroceryItem> inventory = new ArrayList<>();
inventory.add(new GroceryItem("apple"));
inventory.add(new GroceryItem("pear"));
inventory.add(new GroceryItem("banana"));
inventory.add(new GroceryItem("orange"));
inventory.add(new GroceryItem("beetroot"));
inventory.add(new GroceryItem("onion"));
inventory.add(new GroceryItem("lettuce"));
inventory.add(new GroceryItem("carrot"));
inventory.add(new GroceryItem("guava"));
inventory.add(new GroceryItem("lychee"));
inventory.add(new GroceryItem("kiwi"));
int n = inventory.size();
for (int i = 0; i < n-1; i++) {
for (int j = 0; j < n-i-1; j++) {
if (inventory.get(j).compareTo(inventory.get(j+1)) > 0) {
// swap inventory[j+1] and inventory[j]
GroceryItem temp = inventory.get(j);
inventory.set(j, inventory.get(j+1));
inventory.set(j+1, temp);
}
}
}
System.out.println();
}
}
The above code creates a List of GroceryItem objects that contains eleven elements. After populating the List, the bubble sort is performed in the two, nested for loops. Finally the sorted List is printed.
Note that class GroceryItem also implements method toString() so as to make the output human-readable when printing an instance of GroceryItem.
If, in future, you need to use GroceryItem as the key for a java.util.HashMap, then GroceryItem will need to override method hashCode() and if a class overrides method hashCode() then it should also override method equals(). Hence that is why the above code includes those overridden methods. Note that none of those methods – equals(), hashCode() and toString() – are required for the bubble sort.
The oputput when running the above code is:
[apple, banana, beetroot, carrot, guava, kiwi, lettuce, lychee, onion, orange, pear]
I have to order an arrayList that contains lines from a file by account ID and then by salary to get this result:
CuentaAhorro : 11111111A (Alicia) Saldo 111,11
CuentaAhorro : 12345678A (Lucas) Saldo 5100,00
CuentaCorriente: 22222222B (Peio) Saldo 222,22
CuentaAhorro : 33333333C (Isabel) Saldo 4433,33
CuentaCorriente: 33333333C (Isabel) Saldo 3333,33
CuentaAhorro : 87654321A (Asier) Saldo 3000,00
My arrayList calls the compareTo method from Bank.java.
public void ordenarCuentas() {
Collections.sort(cuentas);
}
The call is to the method compareTo in an abstract class called Account with the comparable interface:
#Override
public int compareTo(Cuenta unaCuenta) {
Cliente unTitular = unaCuenta.titular;
if(unTitular.toString().equals(unaCuenta.titular.toString()) == true) {
return 0;
// if(saldo < unaCuenta.saldo) {
// return -1;
// } else if (saldo > unaCuenta.saldo) {
// return 1;
// } else {
// return 0;
// }
}
return -1;
}
I need to check if the object 'Cuenta unaCuenta' passed as a parameter has the same account number as another and then sort by the amount of money in the account, however I am not sure how to get the condition right, as you can see, with the commented if I get the salary in the right descending order but not the account IDs.
The object Cuenta unaCuenta contains titular which contains account number and name.
The object Cliente unTitular contains the account number and name.
Could somebody lend me a hand please?
I am not able understand it very clearly because of language barrier
But if you have a arraylist you can call sort method on it an pass a comparator to get the desired sorting , something like below.
It is just to give you an idea
ArrayList<String> list = new ArrayList<>();
list.sort(new Comparator() {
#Override
public int compare(Object o1, Object o2) {
if(o1.account.equals(o2.account)) return 0;
return o1.amount - o2.amount;
}
});
as Lambda
ArrayList<String> list = new ArrayList<>();
list.sort((o1,o2) ->
if(o1.account.equals(o2.account)) return 0;
return o1.amount - o2.amount;
});
Thank you everyone for the comments. Next time i'll translate the Spanish code to English. I'll post my solution incase someone comes across this question.
(in my case I had to use a comparable interface and a compareTo method).
#Override
public int compareTo(Account anAccount) {
String b = this.title.toString();
Client aTitle = anAccount.title;
String c = aTitle.toString();
if(b.compareTo(c) == 0) {
if(balance == anAccount.balance) {
return 0;
} else if (balance < anAccount.balance) {
return 1;
} else {
return -1;
}
}
return b.compareTo(c);
}
As stated, I had to compare both object values first, if they are the same I then check the condition of the balance to change the order.
-1 = object is less than the parameter.
0 = when both objects are the same.
1 = the object is more than the parameter.
And I called the method from the Bank.java class with:
Collections.sort(cuentas);
Where cuentas is the ArrayList.
I am having a problem with PriorityQueues, as I am lead to believe it orders on priority however I am not sure what the priority is (I mean what the value is and where it comes from). A priorityQueue can be made with a comparator in the constructor and I have tried this but it does not work.
Queue class:
public JavaPriorityFlightQueue() {
super();
flights = new PriorityQueue(5, new SortQueueViaPriority());
}
Comparator:
import java.util.Comparator;
public class SortQueueViaPriority implements Comparator {
public int compare(Object o1, Object o2){
Flight f1 = (Flight) o1;
Flight f2 = (Flight) o2;
if( f1 == null || f2 == null ){
if( f1 == f2 ) return 0;
else if( f2 == null) return +1;
else return -1;
}
Integer i1 = (Integer) f1.getPriority();
Integer i2 = (Integer) f2.getPriority();
return i2.compareTo(i1);
}
}
Priority is an int value which is part of the flight class. I test this.
JavaPriorityFlightQueue flightQueue = new JavaPriorityFlightQueue();
Flight flight1 = new Flight("0001",9);
Flight flight2 = new Flight("0002",7);
Flight flight3 = new Flight("0003",1);
Flight flight4 = new Flight("0004",2);
Flight flight5 = new Flight("0005",1);
However the PriorityQueue is not sorted, and when I check it the value 9 is never compared to anything and the result is nothing is sorted. the compare class SortQueueViaPriority is copy and pasted from another class where the class sorts perfectly.
I suggest you try the following example. If you use PriorityQueue as a queue, the entries are removed in order.
import java.util.Comparator;
import java.util.PriorityQueue;
public class Main {
public static void main(String... args) {
PriorityQueue<Flight> flights = new PriorityQueue<Flight>(5, new SortQueueViaPriority());
flights.add(new Flight("0001", 9));
flights.add(new Flight("0002", 7));
flights.add(new Flight("0003", 1));
flights.add(new Flight("0004", 2));
flights.add(new Flight("0005", 1));
while (!flights.isEmpty())
System.out.println(flights.remove());
}
}
class SortQueueViaPriority implements Comparator<Flight> {
#Override
public int compare(Flight f1, Flight f2) {
return Integer.compare(f2.getPriority(), f1.getPriority());
}
}
class Flight {
private final String name;
private final int priority;
Flight(String name, int priority) {
this.name = name;
this.priority = priority;
}
public int getPriority() {
return priority;
}
#Override
public String toString() {
return "Flight{" +
"name='" + name + '\'' +
", priority=" + priority +
'}';
}
}
prints
Flight{name='0001', priority=9}
Flight{name='0002', priority=7}
Flight{name='0004', priority=2}
Flight{name='0003', priority=1}
Flight{name='0005', priority=1}
Note: PriorityQueue sorts entries such that only the first element will be the smallest. If you iterate over the queue, you will see all the elements, but they may or may not be in order.
Issue is Iterator.As Documented in Java doc of PriorityQueue#iterator
Returns an iterator over the elements in this queue. The iterator does not return the elements in any particular order.
As toString uses iterator it will not get printed in order. Or if you use loop based on iterator then also it will be in order.
And in the Java doc of PriorityQueue
The queue retrieval operations poll, remove, peek, and element access the element at the head of the queue.
To get results in order you will have to use one of these methods.
Instead of Comparator just use Comparable interface.
Your Flight class should implement Comparable interface. Then you need to override the compareTo() method. In that method you can add your own logic for sorting based on the property you need.
Just like this way:
#Override
public int compareTo(Object obj) {
// TODO Auto-generated method stub
Flight f = (Flight)obj;
if(this.a <f.a){
return 1;
}else{
return -1;
}
}
I'm new to Java and I'm trying to arrange an arrayList of terms in alphabetical order. (A term is defined as a char and an int) (e.g. {Term('Z',4),Term('C',3),Term('Q',2) ...} )
My code is as follows:
public Term nextElement()
{
Term max = terms.get(0);
char maxtest = max.getElement();
for (int i = 1; i < terms.size(); i++){
Term tester = terms.get(i);
char maxtest2 = tester.getElement();
if (maxtest2 > maxtest) {
tester = max;
}
}
return max;
}
Why isn't this working? and how do I accomplish this?
My arrayList is called term filled with type Term
Your problem with this line of Code. Your class is not a Type of Comparable So, On which property or criteria compareTo() method will compare these two objects ???
res = maxtest.compareTo(maxtest2); //Your maxtest object is not Comparable Type.
You must need to make your class Term Comparable type. and , Override the method compareTo() as per your need.
You have not mentioning the variable's or structure of your class Term . So, I am assuming that your class have such kind of Structure .
public class Term implements Comparable<Term> {
private Character alpha;
private int number;
//getter and setters +Constructors as you specified
....
....
...
.....
// Now Set a criteria to sort is the Alphanumeric.
#Override
public int compareTo(Term prm_obj) {
if (prm_obj.getAlpha() > this.alpha) {
return 1;
} else if (prm_obj.getAlpha() < this.alpha) {
return -1;
} else {
return 0;
}
}
Now Your Class become a comparable Type. So you may apply Collections.sort(Collection obj) which automatically sort your ArrayList<Term>.
Here I write a demo for this.
public static void main(String... args){
List<Term> obj_listTerm = new ArrayList<>();
//add all the data you given in question
obj_listTerm .add(new Term('Z', 4));
obj_listTerm .add(new Term('Q', 2));
obj_listTerm .add(new Term('c', 3));
// print without Sorting your Term ArrayList.
System.out.println("This is the list unsorted: " + myTermList);
// Sort Using Collections.sort() Method.
Collections.sort(myTermList);
// After applying sort() you may see your Sorted ArrayList.
System.out.println("This is the list SORTED: " + myTermList);
}
You can use the Collection class and sort the list of term you have, you need only to make the class Term comparable
Example:
public class Term implements Comparable<Term> {
.....
// .....
// criteria to sort is the char
#Override
public int compareTo(Term o) {
if (o.getLetter()> this.letter) {
return 1;
} else if (o.getLetter() < this.letter) {
return -1;
} else {
return 0;
}
}
public static void main(String[] args) {
// test
List<Term> myTermList = new ArrayList<>();
myTermList.add(new Term('Z', 4));
myTermList.add(new Term('Q', 2));
myTermList.add(new Term('c', 3));
// check how the look like
System.out.println("This is the list unsorted: " + myTermList);
// now sort them
Collections.sort(myTermList);
// check how the look like
System.out.println("This is the list SORTED: " + myTermList);
}
Edit>
if you dont want to implement comparable then modify this:
res = maxtest.compareTo(maxtest2);
because this is not valid since maxtest and maxtest2 are primitives and not objects...
use instead
res = Character.compare(maxtest, maxtest2);
and then use the result to verify your logic and make decisions:
if (res >1) {
System.out.println("bigger");
}else if (res<1) {
System.out.println("smaller");
}else {
System.out.println("same");
}
I'm having issues with removing duplicate objects from an ArrayList. Im parsing XML into what i call an IssueFeed object. This consists of a symptom, problem, solution.
Most of my objects are unique and don't share a symptom, problem, solution but some share the same symptom but have a different problem.
Im trying to accomplish several things.
Capture objects that share the same symptom as a duplicate Arraylist
Remove the duplicate items from the main list, leaving at least 1 item with that symptom to be displayed.
When the user clicks on the item that we know has duplicates, set the duplicate data Arraylist in my listview/adapter.
Steps i've taken.
I've tried sorting the objects and i am able to capture the duplicates, however not sure how to remove all but one from the main list.
2 Loops between the list and looking for objects that aren't themselves and symptom = symptom and then remove and update my duplicate array and main array.
Some code
IssueFeed - object
public IssueFeed(String symptom, String problem, String solution) {
this.symptom = symptom;
this.problem = problem;
this.solution = solution;
}
public String getSymptom() {
return symptom;
}
public String getProblem() {
return problem;
}
public String getSolution() {
return solution;
}
My ArrayList<IssueFeed>'s
duplicateDatalist = new ArrayList<IssueFeed>(); // list of objects thats share a symptom
list_of_non_dupes = new ArrayList<IssueFeed>(); // list of only objects with unique symptom
mIssueList = mIssueParser.parseLocally(params[0]); // returns ArrayList<IssueFeed> of all objects
I can obtain the duplicates by the following sort code below.
Collections.sort(mIssueList, new Comparator<IssueFeed>(){
public int compare(IssueFeed s1, IssueFeed s2) {
if (s1.getSymptom().matches(s2.getSymptom())) {
if (!duplicateDatalist.contains(s1)) {
duplicateDatalist.add(s1);
System.out.print("Dupe s1 added" + " " + s1.getSymptom() + ", " + s1.getProblem() + "\n");
}
if (!duplicateDatalist.contains(s2)) {
duplicateDatalist.add(s2);
System.out.print("Dupe s2 added" + " " + s2.getSymptom() + ", " + s2.getProblem() + "\n");
}
}
return s1.getSymptom().compareToIgnoreCase(s2.getSymptom());
}
});
Now i need to create the new list of non dupes, This code only added all of the objects. :/
for (int j = 0; j < mIssueList.size(); j++) {
IssueFeed obj = mIssueList.get(j);
for (int i = 0; i < mIssueList.size(); i++) {
IssueFeed obj_two = mIssueList.get(j);
if (obj.getSymptom().matches(obj_two.getSymptom())) {
if (!list_non_dupes.contains(obj_two)) {
list_non_dupes.add(obj_two);
}
break;
} else {
if (!list_non_dupes.contains(obj_two)) {
list_non_dupes.add(obj_two);
}
}
}
}
If you could modify the IssueFeed object the consider overrding the equals() and hashCode() methods and use a set to find duplicates. Eg
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
class IssueFeed {
private String symptom;
private String problem;
private String solution;
public IssueFeed(String symptom, String problem, String solution) {
this.symptom = symptom;
this.problem = problem;
this.solution = solution;
}
public String getSymptom() {
return symptom;
}
public String getProblem() {
return problem;
}
public String getSolution() {
return solution;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((symptom == null) ? 0 : symptom.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
IssueFeed other = (IssueFeed) obj;
if (symptom == null) {
if (other.symptom != null)
return false;
} else if (!symptom.equals(other.symptom))
return false;
return true;
}
#Override
public String toString() {
return "IssueFeed [symptom=" + symptom + ", problem=" + problem
+ ", solution=" + solution + "]";
}
}
public class Sample {
public static void main(String[] args) {
List<IssueFeed> mainList = new ArrayList<IssueFeed>(
Arrays.asList(new IssueFeed[] {
new IssueFeed("sym1", "p1", "s1"),
new IssueFeed("sym2", "p2", "s2"),
new IssueFeed("sym3", "p3", "s3"),
new IssueFeed("sym1", "p1", "s1") }));
System.out.println("Initial List : " + mainList);
Set<IssueFeed> list_of_non_dupes = new LinkedHashSet<IssueFeed>();
List<IssueFeed> duplicateDatalist = new ArrayList<IssueFeed>();
for(IssueFeed feed : mainList){
if(!list_of_non_dupes.add(feed)) {
duplicateDatalist.add(feed);
}
}
mainList = new ArrayList<IssueFeed>(list_of_non_dupes); // Remove the duplicate items from the main list, leaving at least 1 item with that symptom to be display
list_of_non_dupes.removeAll(duplicateDatalist); // list of only objects with unique symptom
System.out.println("Fina main list : " + mainList);
System.out.println("Unique symptom" + list_of_non_dupes);
System.out.println("Duplicate symptom" + duplicateDatalist);
}
}
You should iterate through the ArrayList twice. Using this approach, you don't even need to sort the ArrayList by duplicates (Collections.sort is an O(n log n) operation) and can process the list in linear time. You also don't need to override equals() and hashCode() for IssueFeed objects.
In the first iteration, you should fill a HashMap of the symptoms hashed against the number of occurrences in the ArrayList. It would probably be
class SymptomInfo {
int incidence;
boolean used;
}
HashMap<String, SymptomInfo> symptomIncidence = new HashMap<String, SymptomInfo>();
However, you may want to use a thread-safe HashMap data structure if you are reading and writing to the HashMap from multiple threads.
In the second iteration through the ArrayList, you should look up the incidence value from the hashmap and find the total number of occurrences of that symptom. This is a quick and easy way to find out whether the object should be added to duplicateDataList or list_of_non_dupes. Also, the first time you encounter an object with a particular symptom value, you can set used to true. So, if you encounter an object where used is true, you know it is a duplicate occurrence and can remove it from the main list.