Java LinkedList contains() seems to fail - java

I'm trying to make a LinkedList containing the "best of" of an offspring in an evolutionary algorithm.
Therefore, I have my own custom add() method:
public boolean add(Virus v) {
if((this.size()< ConfigObject.getInstance().surviverPopulation //if the size of the new population is < surviverPopulation
|| v.getFitness() > this.getLast().getFitness()) //or the fitness is higher than that of the last member
&& v.getFitness() > 0.0 //and the fitness is higher than 0
&& !v.isDead() //and the virus is alive
&& !this.contains((Virus)v)) { //and it is not yet in the list
super.add(v); //add it normally
Collections.sort(this, new Comparator<Virus>() { //sort the list
//define parameter to sort by
#Override
public int compare(Virus virus1, Virus virus2) { //with custom comparator
if(virus1.getFitness() == virus2.getFitness()) {
return 0;
} else if (virus1.getFitness() > virus2.getFitness()) {
return -1;
} else {
return 1;
}
}
});
}
while(this.size() > 300) {
this.removeLast();
}
return true;
}
With this method, I get a LinkedList of limited size which is also sorted and only contains the "best" objects. (The rest of the LinkedList-class is unaltered).
However, when I use this class, something strange happens:
for(Virus parent : this.currentPopulation) { //for every virus in the current population
for(GraphNode child : parent.getChildren()){ //get all the children, and for each child
temp = (Virus) child;
if(!temp.isDead() && !newCurrentPopulation.contains(child)) { //try to add the child if it's not dead
newCurrentPopulation.add((Virus) child); //and not already in the list
} //(list only takes a maximum of <surviverPopulation>
} //and only the strongest ones, see declaration)
newCurrentPopulation.add(parent); //also try to add the parent to the list if
} //still alive
int j = 0;
for(Virus parent : this.currentPopulation) { //for every virus and its children in the current population
for(GraphNode child : parent.getChildren()){ //check if it made it into the new population
if(!newCurrentPopulation.contains((Virus) child)) {
toRemove.add((Virus) child); //if not, memorize to delete it later
}
}
if(!(newCurrentPopulation.contains((Virus) parent))); {
toRemove.add(parent); //do the same for the parent virus
}
}
It works quite fine for the children, but not for the parent. The debugging info shows that even though the parent (identifiable by an id) is in the newCurrentPopulation, it will be included into the toRemove list (where it's also identifiable by the same id).
Also, I did not override the equals-method for the Virus-class or any of its superclasses. I'm probably missing something quite obvious here but I can't see it.

It is something extremely obvious indeed: the last if-statement is followed by a semicolon and not the {}.

The contains method internally calls the equals method of Virus class.
The default equals method provided by the Object class uses == operator, which in your case returns false.
You have to override the equals method in Virus class and compare the objects with id.

Related

Modified LinkedList (2 integers per node) with ListIterator

I'm writing a code to save, delete and load a person's height and weight data. I have created 2 classes:
class Person {
private int height;
private int weight;
public Person(int h, int w) {
height = h;
weight = w;
}
public int getHeight() {
return height;
}
public int getWeight() {
return weight;
}
public String getValues() {
return ("Height "+height+" and weight "+weight);
}
}
class DataModified { //Problem in this class
private LinkedList<Person> lList;
private ListIterator<Person> lIter;
public DataModified() {
lList = new LinkedList<Person>();
lIter = lList.listIterator();
}
public void save(Person p) {
Person p1, p2; //p1: Data needed to be saved
p1 = new Person(p.getHeight(), p.getWeight()); //p2: Data already on the list
boolean alreadyExist = false;
lIter = lList.listIterator();
while(lIter.hasNext()) {
p2 = lIter.next();
if ((p2.getHeight() == p1.getHeight()) && (p2.getWeight() == p1.getWeight())) {
alreadyExist = true;
}
}
if(alreadyExist) {
System.out.println("Person: " + p1.getValues() + " had already been on the list.");
}
else {
lIter.add(p1);
System.out.println("Person: " + p1.getValues() + " is added to the list.");
}
}
public void delete(Person p) {
Person p3, p2; //p3: Data needed to be deleted
p3 = new Person(p.getHeight(), p.getWeight());
boolean alreadyExist = false;
lIter = lList.listIterator();
while(lIter.hasNext()) {
p2 = lIter.next();
if ((p2.getHeight() == p3.getHeight()) && (p2.getWeight() == p3.getWeight())) {
alreadyExist = true;
}
}
if(alreadyExist) {
lIter.remove();
System.out.println("Person: " + p3.getValues() + " is deleted from the list.");
}
else {
System.out.println("Person: " + p3.getValues() + " is not on the list.");
}
}
public void load() { //Problem
lIter = lList.listIterator();
Person p2;
for(int i = 1; lIter.hasNext(); i++){
p2 = lIter.next();
System.out.println("Person "+i+" has "+p2.getValues());
}
}
}
I had tested these 3 methods from class DataModified: I first save data from 3 persons, then delete 1 person and load the rest. However, the last method prints not the 2 persons on the list, but the person I have deleted before.
My question are:
What is wrong with my code? Why did the load() method work like that?
I noticed that after iterating, I can only modified the lIter. So are lList and lIter the same list or 2 separated lists? If they are not the same, how can I give lList the data from lIter?
Is there a way to stop the iteration of a list?
As others are pointing out, you definitely have a bug in your delete method. As written, if the target Person is found in the list, then the last Person in the list will be removed, not the target. You really need to be able to cut out of the while loop when you find the person and remove it immediately instead of continuing the loop.
To answer your questions:
What's wrong? The bug in delete that removes the wrong Person.
Are lList and lIter the same list? Conceptually yes, technically no. lList is the list itself, and lIter is the Iterator acting on that list. It's not a list itself. It's an Iterator. But the data it's working on is definitely the same list.
How to stop iteration? You have a few options. The easiest for how your code is currently written is a break statement. It stops execution of the current loop and resumes executing outside the block. In both your add and delete methods, it would make sense to break right after alreadyExist is set to true. Another option, suggested first by jiveturkey, is to add alreadyExist as a condition to the while loops. Then you'll only continue iterating if both there are more items to iterate over and alreadyExist hasn't yet been set to true. A third option would be to do the real work (i.e delete) as soon as you find the Person and then return from the method entirely.
Beyond that, some unsolicited general advice :)
You're comparing Person objects in multiple methods. Over time, this will get hard to maintain, so it would be better to define the comparison in one place. Java comes with an equals method for this. It's in every Object, but the default implementation won't help you, so you want to override it. In your case, you consider two distinct Person objects to be conceptually equal if their heights and weights are equal. So override the equals() method in Person to return true iff the height and weight are equal. See How to override equals method in java or http://users.csc.calpoly.edu/~gfisher/classes/102/info/howToOverrideEquals.html for some tips. If you override equals, you also need to override hashCode.
You're making copies of the Person parameters. The exact object being passed in is not the actual object being added or deleted from the list; the copy is. You could just use the paremeter. In the best case, you currently have an unnecessary performance hit (creating extra objects). In the worst case you'll hit bugs.
lIter is set both in the constructor and in every method. If you don't need to store its current state across method calls, then it should probably be just a local variable, used for a method and then discarded.
getValues() is currently just being used to make the object human-readable. That's a common problem, and the task given to toString(), also defined in Object and overridable in any class you write. All you'd need to do to take advantage of it is rename getValues to toString. Then you could just use it in a log message directly. Example below.
Here's how I would then rewrite delete, assuming a good equals method in Person, and getValues renamed to toString:
public void delete(Person p) {
boolean alreadyExist = false;
ListIterator definitelyNotLIter = lList.listIterator();
while(definitelyNotLIter.hasNext()) {
Person current = definitelyNotLIter.next();
if (p.equals(current)) {
alreadyExist = true;
definitelyNotLIter.remove();
// Option 1:
break; // next line to execute will be the if(alreadyExist) block
// Option 2:
// put your successful delete logging here
// return;
// and leave the failed delete logging outside the loop
// Option 3:
// Do nothing. The looping will continue, and you'd have a deleteAll method, where multiple items would get deleted if you managed to get duplicates in the list.
// You actually wouldn't need alreadyExist any more.
// I'd go with option 1, myself
}
}
if(alreadyExist) {
System.out.println("Person: " + p + " is deleted from the list."); // p.toString() will get called
}
else {
System.out.println("Person: " + p + " is not on the list."); // p.toString() will get called
}
}
In delete(), once you find your Person you set alreadyExist to true the first time you find someone and keep going. So once it's set, it's set for EVERYONE. If you find your Person in the list in position 1, you'll delete him, but then you'll delete the next person and so on. All of your while loops need to say.
while (!alreadyExists && lIter.hasNext()) {
p2 = lIter.next();
if ((p2.getHeight() == p1.getHeight()) && (p2.getWeight() == p1.getWeight())) {
alreadyExist = true;
lIter.remove();
}
}
// Delete the if/else code
You should probably get rid of the member variable:
private ListIterator<Person> lIter;
From Documentation:
void remove() Removes from the list the LAST element that was returned
by next() or previous()
But when you reach the required Person Object, you continue iteration the next Person Object.
What you need is to break the while loop once it finds the target object.
if ((p2.getHeight()==p3.getHeight())&&(p2.getWeight()==p3.getWeight())){
alreadyExist = true;
break;
}
Now the last element is the required Object, you can now use remove().
if(alreadyExist) {lIter.remove();}
The problem is in your delete method:
You loop through the entire list before removing anything. ListIterator.remove only deletes the last item returned by next(). You need to break when you find the item that already exists:
while(lIter.hasNext()) {
p2 = lIter.next();
if ((p2.getHeight() == p3.getHeight()) && (p2.getWeight() == p3.getWeight())) {
alreadyExist = true;
break;
}
}
Additionally, the way you are comparing Person objects should really be done in a equals() method, as described here.
Finally, your creation/use of an extra Person that is a duplicate of parameter p is entirely unnecessary here. Just use p instead of p1 (in save) and p3 (in delete).

Why does .contains method on ArrayList of custom instances work?

I've been developing a small application for work, and I've come across something I can't figure out.
In the following code, I have an ArrayList of a Custom Class called 'Product' that contains data of type 'String'. I use the .contains method on this ArrayList to ensure it doesn't contain a certain String.
My IDE gives me the warning of 'Suspicious call to java.util.Collections.contains: Given object cannot contain instances of String (expected Product)'.
I completely understand the above message, because I'm comparing two different Types, so how can it ever evaluate correctly? I'm thinking it must be because the 'Product' class contains the data I want to compare, it is defaulting to using the toString method on the Product class (I override this in the Class) and comparing it with the String I want to compare it against.
It seems like JVM black magic to me.
private void createOrderListing(List<String[]> orderList)
{
//For each line of the order list file
for(String[] s : orderList)
{
if(s.length >= 28) //OrderLine should be of this length
{
if (!s[0].equalsIgnoreCase("ProductCode") && !s[0].isEmpty()) //Makes sure we're not including headers
{
//How does this bit work?
if(!productListing.contains(s[0]))
{
OrderLine order = new OrderLine();
//References product code of Product against Order Line, if match, then pack sizes and other basic fields ammended as appropriate
boolean productFound = false;
for (Product p : productListing)
{
if (s[0].contentEquals(p.getProductCode()))
{
order.initialAmendOrderLine(p.getProductCode(), p.getProductName(), p.getPackSize(), p.getProductType());
productFound = true;
}
}
if(productFound)
{
order.setOrderValues(s);
orderListing.add(order);
}
}
//System.out.println("\nOrder Product is: " + order.getProductName()+ "\nOrder Pack Size is: " + order.getInternalPackSize());
}
}
}
}
UPDATE
The reason this works as pointed out in the comments is that the block is always true (the .contains method is always false, the ! inverses this, hence true). Sorry for the confusion and pointing out my carelessness.
Here is an implementation of contains method in ArrayList that I have in OpenJDK:
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
Basically, there is nothing complex in it. It iterates through the all elements of your ArrayList and checks whether your given object is equal to the current one. If the condition is true then element exists in the list.
So let's imagine that you are passing String "SomeValue" to this method. Elements of ArrayList are iterated and following action is executed: "SomeValue".equals(elementData[i]) where elementData[i] is a product.
Since equals method of String class cannot compare String with a Product it returns false and as a result, you get false from contains method.
To fix this situation you can iterate over ArrayList manually and compare some Product's field with your string. E.g. you can implement following contains method:
public boolean contains(List<Product> products, String yourStringValue) {
for (Product p : products) {
if(p.getProductCode().equals(yourStringValue)){
return true;
}
}
return false;
}
productListing is a list of Product objects. Yet you are asking the list if it contains a specific String object -- which shouldn't ever happen.
What you should do is check if your Product#getProductCode is equal to your specific String. This can be acheived by using streams:
if(!productListing.contains(s[0])) // replace this
// with this
if (!productListing.stream().filter(o -> o.getProductCode().equals(s[0])).findFirst().isPresent())
What does this code do? It checks all your Product elements to find one whose myStringData attribute is equal to the String you're comparing.
since contains relays on equals implementation, when you do
if(!productListing.contains(s[0]))
you are asking the list OF ARRAYS OF STRINGS if its contains a String.
that will return always false because the type are different, so is not that is working at all, is that your condition will always return false

Recursive implementation of a method

I'm new to Java and still trying to wrap my head around recursion.The function below returns true at the very first intersection between the two sorted lists list x and list y.
public static boolean checkIntersection(List<Integer> x, List<Integer> y) {
int i = 0;
int j = 0;
while (i < x.size() && j < y.size()) {
if (x.get(i).equals(y.get(j))) {
return true;
} else if (x.get(i) < y.get(j)) {
i++;
} else {
j++;
}
}
return false;
}
Now I've been trying to implement it using recursion instead, and I know that there should be a base case which is an empty list in this case and then try to reduce the list by excluding one element at a time and feed it back to the same recursive function, but I can't work out how to check for intersection as I pass the rest of the list over and over.
public static boolean recursiveChecking(List<Integer> x,List<Integer> y) {
if(x.size() == 0){
return false;
}
else {
return recursiveChecking(x.subList(1, x.size()-1), y);
}
}
Any help would be highly appreciated. Thank you.
General approach to making something recursive is to think of two things:
When can I produce an answer trivially? - An answer to this question lets you code the base case. In your situation, you can produce the answer trivially when at least one of two lists is empty (the result would be false) or the initial elements of both non-empty lists are the same (the result would be true)
How do I reduce the problem when the answer is non-trivial? - An answer to this question lets you decide how to make your recursive call. In your case you could, for example, remove the initial element of one of the lists before making the recursive call*, or pass ListIterator<Integer> in place of List<Integer> for a non-destructive solution.
*Of course in this case you need to take care of either adding your numbers back after the call, or make a copy of two lists before starting the recursive chain.
As the lists are ordered, your recursion should remove the first element of the list with the smaller first value. Then you have to return true, if both lists start with the same number and false if any of the lists is empty. Otherwise you keep removing elements. This would look something like this (This code is untested):
public static boolean recursiveChecking(List<Integer> x,List<Integer> y) {
if(x.size() == 0 || y.size() == 0){
return false;
} else if (x.get(0).equals(y.get(0))) {
return true;
} else {
if (x.get(0) < y.get(0)) {
return recursiveChecking(x.subList(1, x.size()-1), y);
} else {
return recursiveChecking(x, y.subList(1, y.size()-1));
}
}
}

Java Circular Linked List,Remove Node not working properly

Ok so i need to deleted items from a circular list,as part of a bigger program that isnt working, and i cant seem to delete the last node passed in to the delete method, if the index passed in is 1 it will delete the 1st node in list and replace it, but when there is only one node left it has nothing to reference off, been at this hours. i will leave my delete method here
public void delete(int index)
{
if(Node.numOfUsers == 1)
{
first=null;
return;
}
//make curr the same as first node
int i = 1;
curr=first;
//if index passed in is 1, make temporary node same as one after first node
// if(size<1)
// {
// System.out.println("ok so this is where we are at");
// }
if(index==1)
{
temp=first.nextNode;
while(temp.nextNode!=first)
{
temp=temp.nextNode;
}
temp.nextNode=temp.nextNode.nextNode;
first=curr.nextNode;
}
else
{
//as long as i is not equal to node index-1 move current on 1 and increment i by 1
while(i != index-1)
{
curr=curr.nextNode;
i++;
}
//curr.nextNode is pointing to the node index we want and making it equal to one index above it
curr.nextNode=curr.nextNode.nextNode;
}
Node.numOfUsers--;
int size=size();
}
}
Looks like you're keeping track globally of a number of users. If this behaves the way I think it would, you could just have a small check at the beginning of this method so that if it is zero, you don't follow through with any of the logic following it.
if(Node.numOfUsers == 0) return;
This will make it so you don't bother executing any of the other logic.
A slightly better methodology to this problem might be to use the Node you want to delete as a parameter, rather than its index. This way you can avoid having to keep track of indices inside your data structure.
e.g.
public void delete(Node n) {
if(Node.numOfUsers == 0 || n == null) return; // 0 nodes or null parameter.
Node temp = first;
if(temp.next == null) { //only one node
temp = null; //simply delete it
} else {
while(temp.next != n) {
temp = temp.next;
if(temp == first) { //if we circle the entire list and don't find n, it doesn't exist.
return;
}
}
temp.next = n.next; // perform the switch, deleting n
}
}
EDIT: The above code follows the assumption that you'll have references to the node you want to delete. If this is not the case, using indices is just as good. You may also consider comparing values, however this would require you to assume that you have unique values in your nodes (and I don't know what you're restrictions are).
The logic for comparing values would be identical to the above, however instead of comparing if(temp == n) for example, you would compare if(temp.data.equals(n.data)). The use of the .equals() method is specifically for the String type, but you could modify it to work with whatever data type you are expecting, or better yet write a custom .equals method that allows the use of Generics for your abstract data type.

Is there any way I can return a value from a loop and continue from where I left off?

Is there any way I can return a value from a loop and continuing from where I left off ?
In the following snippet, I want to return the current value of currVm. But I am unable to do so.
In the innermost loop of the snippet :
while(c <= currVm) {
allocatedVm(currVm);
c++;
}
a function named allocatedVm is called. I want to return the value of currVm and start again from where I left off. Is there any way out ?
#Override
public int getNextAvailableVm() {
Set<String> dataCenters = confMap.keySet();
for (String dataCenter : dataCenters) {
LinkedList<DepConfAttr> list = confMap.get(dataCenter);
Collections.sort(list, new MemoryComparator());
int size = list.size() - 1;
int count = 0;
while(size >= 0) {
DepConfAttr dca = (DepConfAttr)list.get(count);
int currVm = dca.getVmCount();
int c = 0;
while(c <= currVm) {
allocatedVm(currVm); // RETURN currVm
c++;
}
count++;
size--;
}
}
}
The best approach would probably be to write a method returning an Iterable<Integer>. That's not as easy in Java as it is in languages which support generator functions (e.g. C# and Python) but it's still feasible. If the code is short, you can get away with a pair of (nested) anonymous inner classes:
public Iterable<Integer> foo() {
return new Iterable<Integer>() {
#Override public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
// Implement hasNext, next and remove here
};
}
};
}
In your case I'd be tempted to break it into a separate non-anonymous class though, just for simplicity.
Anyway, the point of using Iterable is that an Iterator naturally has state - that's its purpose, basically. So it's a good fit for your requirements.
Another rather simpler approach would be to return all of the elements in one go, and make the caller perform the allocation on demand. Obviously that doesn't work well if there could be a huge number of elements, but it would be easier to understand.
not sure i understand what you need, but:
if you wish to notify the caller of the method that you've got a value during the running of the method, but don't wish to exit the method just yet, you can use listeners.
just create an interface as a parameter to your function, and have a function inside that will have the object as a parameter.
example:
interface IGotValueListener
{
public void onGotValue(MyClass obj);
}
public int getNextAvailableVm(IGotValueListener listener)
{
...
if(listener!=null)
listener.onGotValue(...);
}
now , for calling the method, you do:
int finalResult=getNextAvailableVm(new IGotValueListener ()
{
... //implement onGotValue
};
You can return from anywhere in your method , by just putting the return keyword. If you want to put a functionality to resume ur method from different places then u need to factor ur method in that way. You can use labels and if statements, set some static variables to mark the last execution place. If your application is not multi-threaded then u need not to worry with the use of static variable synchronization. Also if your method is too big and becoming hard to follow/read, then think about breaking it into smaller ones.

Categories

Resources