I have the following code
public void makeBaby() {
String duplicate;
boolean full = false;
boolean same = false;
for (int i = 0; i < park.length; i++) {
if (park[i] == null) {
full = false;
} else if (i == park.length - 1 && park[i] != null) {
full = true;
}
if (i != park.length - 1) {
for (int j = 1; j < park.length; j++) {
if (park[i].name.equals(park[j].name)) {
same = true;
duplicate = park[i].name;
}
}
}
if (!full) {
System.out.println("The zoo is full. Cannot make any more babies");
} else if (!same) {
Animal duplicate = new Animal((float) 0.1 * park[i].mass,park[i].name, park[i].legs);
addAnimal(duplicate);
}
}
}
As may be able to see in the code, I have to see if the array called park is full and if not, I need to make a baby animal. but before that, I also need to check if there are 2 animals that have the same type(name).
But I am experiencing problems with the line
Animal duplicate = new Animal((float) 0.1 * park[i].mass,park[i].name, park[i].legs);
addAnimal(duplicate);
because the somehow java does not recognize the duplicate as the duplicate I set in the if statement above.
It is simply creating an animal called duplicate which is not what I want to do..
There are some other things that don't add up. For example:
full is declared as false. In the first if-statement:
if (park[i] == null) {
full = false;
which is already known.
If i am not mistaken:
(!full)
is read as false and is meant to be executed when full = true.
(full)
same goes for (!same)
I am no coding genius, so correct me if i'm wrong. :)
You have two variables each named duplicate, I suspect that this is confusing you.
You have variable
String duplicate;
and you have
Animal duplicate
What is your intention? they are different types.
I suspect you mean:
Animal theNewBaby ...
addAnimal(theNewBaby);
And somewhere you intend the name of the new baby to be the String you stored in duplicate. As we can't see your Animal() constructor we don't know.
You have multiple problems here... For one you have two duplicate variables... one String and one Animal. So depending on which parameter your addAnimal() method takes you might be grabbing the wrong duplicate.
Secondly, I don't believe your "Same" code check is going to work as you are looping through the same list twice. Unless you exclude the first found animal from your second j loop you are always going to find a match even when there is only one animal.
That might work for amoebas but not for elephants! :-)
You only have to rename your variable duplicate(for example sDuplicate with the type as prefix), there is no other way if you want to give addAnimal() the string duplicate you set in the if statement. And add to the if condition:
&& i!=j
then your duplicate check will work.
Related
I am trying to make a function that sifts through an array of objects that inherit from one abstract class. The function takes in the item to look for as an argument of the abstract class type, and, if it finds the object type, it deletes it. Here is the code:
public void removeItem(MPItem itemDelete){
for (int i = 0; i < myItems.length; i++){
if(myItems[i] instanceof itemDelete){
myItems[i] = null;
break;
}
//If it reaches this point, we hit the end of the array with no item matching.
if(i == myItems.length - 1){
System.out.println("Item to delete not found");
}
}
}
I know that by typing instanceof in the if statement, it tries to find a class named itemDelete, which does not exist. I am trying to make it to where, no matter what item type I pass in the function that are children of the MPItem abstract class, it will see what exact child class it is, find the first instance of that child type in the array, set it to null, and exit the function. Can anyone help with this or direct me to something that will? Thanks!
Assuming that myItems is defined like this:
MPItems[] myItems = ...
You can use generics and the isAssignableFrom method to achieve your goal:
public void removeItem(Class<? extends MPItem> itemDelete){
for (int i = 0; i < myItems.length; i++) {
if (myItems[i].getClass().isAssignableFrom(itemDelete)){
myItems[i] = null;
break;
}
//If it reaches this point, we hit the end of the array with no item matching.
if (i == myItems.length - 1){
System.out.println("Item to delete not found");
}
}
}
To call the function, do this:
foo.removeItem(Something.class);
Side note: myItems[i] = null is not actually deleting anything from the array (at least not in the normal sense). It is simply setting that position in the array to be null (maybe this is actually what you want). If you actually want to remove the element from the array, here is an alternative solution:
public void removeItem(Class<? extends MPItem> itemDelete){
myItems = Stream.of(myItems).filter(i -> !i.getClass().isAssignableFrom(itemDelete)).toArray(MPItem[]::new);
}
However, since this method is reassigning myItems, it may break other parts of your code :/
I'm currently programming on a little project (which is way to specific to explain here) and I got everything working except one part. I've got a List pZiegel by parameter which is modified in recursion. Because it didn't work, I did a little debugging and found the problem: At one point, the list contains exactly one number at the end of the method. Then, the program jumps one recursion depth back. And directly after that, it doesn't contains any numbers anymore. How did it lose the number? Lists as parameters work with pass-by-reference, so it shouldn't just reject it, right?
public void erstelleBaum (Tree pTree, List<Integer> pZiegel, List<Integer> pFugen, int tiefe) {
if (tiefe / n >= maxHoehe) {
System.out.println("hi");
mauerGefunden = true;
alleFugen = pFugen;
}
if (!mauerGefunden) {
pZiegel.toFirst();
while (pZiegel.hasAccess() && !mauerGefunden) {
boolean ziegelHinzufügen = false;
möglich = true;
aktZiegel = pZiegel.getContent();
// ...
if (möglich) {
// ...
pZiegel.remove();
if (pZiegel.isEmpty()) {
ziegelHinzufügen = true;
pZiegel = new List();
for (int i = 1; i <= n; i++) {
pZiegel.append(i);
}
}
// Recursion
erstelleBaum(neuesBlatt, pZiegel, neueFugen, neueTiefe);
// Here, it tells me that pZiegel is empty (at recursion depth 17)
if (ziegelHinzufügen) {
pZiegel.toFirst();
while (pZiegel.hasAccess()) {
pZiegel.remove();
}
pZiegel.append(aktZiegel);
}
else {
pZiegel.toFirst();
while (pZiegel.hasAccess() && pZiegel.getContent() < aktZiegel) {
pZiegel.next();
}
if (pZiegel.hasAccess()) {
pZiegel.insert(aktZiegel);
pZiegel.toFirst();
while (pZiegel.getContent() != aktZiegel) {
pZiegel.next();
}
}
else {
pZiegel.toLast();
pZiegel.append(aktZiegel);
pZiegel.toLast();
}
}
}
pZiegel.next();
}
}
// Here, pZiegel contained one number (at recursion depth 18)
}
I hope, the code isn't too messy. I tried to keep out the parts that doesn't involve pZiegel. And sorry, that the variables are named in german. I didn't want to change them for this post because I know I would forget to change something in the code.
Feel free to ask, if something is unclear.
I believe the pZiegel List reference is being lost at some point. You should check the pZiegel object ID (a number displayed when you inspect the object) to make sure it is the same List instance all over the recursions.
Notice that there's one part of your code that makes the pZiegel identifier reference a new List:
...
if (pZiegel.isEmpty()) {
ziegelHinzufügen = true;
pZiegel = new List(); // <---- this line
for (int i = 1; i <= n; i++) {
pZiegel.append(i);
}
}
...
I believe you are calling the 18th recursion with pZiegel referencing one list (maybe empty). Inside the 18th recursion that line is called and pZiegel starts referencing a new List (realize that the last List still exists and is referenceed by the pZiegiel identifier of the 17th recursion). On the last line of the 18th recursion call you believe you are inspecting the same pZiegiel List from the 17th recursion, but that's not the case.
I'm trying to do a linkedlist for an assigment i have, this ask explicitly to create, from scratch a linkedlist and some derivated types like a queue and a stack, this is just some college homework, and i realize how to make a node class and a linkedlist class, but i'm struggling to create the addAll() method in this linkedlist class, this is what i have.
if i must bet, i say is the Collection c one, but then, i'm trying to add list of stuff there, in order to pass him's content to the new list, obiusly is not ready and obiusly doesn't work.
Can you tell me how i can pass some kind of "proto-list" in order to pass them data inside the new list?
(I know i must use somekind of for(objects) but i'm failing to pass some data through the parameter, which will be the right parameter to put there?)
public boolean addAll(Collection c) {
for (int i = 0; i < (this.listaNodos.size()); i++) {
//for (T someT : c){
// Node newNodo = new Node(someT);
//}
//i know the one down there is not gonna do anything, because
//i'm not accesing the data, but one problem at a time would ya ;)
Node newNodo = new Node(someT);
Node actualNodo = this;
boolean processFinished = false;
try{
if(index >= this.listaNodos.size() || index < 0){
throw new IndexOutOfBoundsException();
}
do{
if(index == actualNodo.getIndex())
{
actualNodo.setData(someT);
processFinished = true;
return true;
}
else
{
actualNodo = actualNodo.nextNode;
}
}while(!processFinished);
return false;
}catch(IndexOutOfBoundsException ex)
{
throw ex;
}
}
return false;
}
Can you tell me how to fix it to make it work?
Any request for clarification, constructive comment, or question would be greatly apreciated too.
Thanks in advance
I assume you already have an add() method of some sort right? If so, you can go over each element in c and add it using the add method:
public boolean addAll(Collection<T> c) {
boolean changed = false;
for (T t:c) {
changed |= this.add(t);
}
return changed;
}
I'm assuming the returned boolean means whether this list has changed, this is how it is defined in the Collection contract: https://docs.oracle.com/javase/7/docs/api/java/util/Collection.html#addAll(java.util.Collection).
You were also missing a generic type for your add method, so I added one. I assume your class definition looks somthing like this?
public class MyLinkedList<T>
Currently on the chapter in my book where we talk about for loops and loops. I have sometimes come across an issue where the method needs me to return something. For example consider my code
below. Basically the exercise is to get all the factors in ascending order. Now heres the issue
As you can see I need a return statement outside of the for loop. Now I guess my book didn't exactly explain this properly, or I didn't understand the concept
of return properly in java, but does our return statement always have to be in the most outer indentation if you will?
The thing is, I don't really want to return anything outside of the for loop. I just want to return i upon that condition. Why doesn't java let me do this?
Whats a good counter-action?
Ever since I started learning loops and for loops, I have been having trouble understanding this. I guess I could just system.out.println(i) instead of returning it? But then what should I return? I could also make it a void type, and then make another method to print it, I guess?
class factors{
private int num;
public factors(int num)
{
this.num = num;
}
public int getFactors()
{
for(int i = 1 ; i<num ; i++)
{
if (num % i == 0)
{
return i;
}
}
// I NEED TO PUT A RETURN STATEMENT HERE
}
}
public class test{
public static void main(String [] args)
{
factors fact = new factors(20);
System.out.println(fact.getFactors());
}
}
IT WORKS NOW ( I dont particularly like my solution)
class factors{
private int num;
public factors(int num)
{
this.num = num;
}
public void getFactors()
{
for(int i = 1 ; i<num ; i++)
{
if (num % i == 0)
{
System.out.println(i);
}
}
}
}
public class test{
public static void main(String [] args)
{
factors fact = new factors(20);
fact.getFactors();
}
}
The thing is, I don't really want to return anything outside of the for loop. I just want to return i upon that condition. Why doesn't java let me do this?
Java lets you do that. There is nothing wrong with returning inside the loop upon reaching the condition.
Java allows you to have multiple return statements, so adding another return 0; after the loop is allowed.
Java returns once it hits the first return statement, and other return statements are not executed (the method isn't executed anymore) (except for some rare edge cases with try-catch and return, but thats another story entirely).
But why is it required?
Java requires that for all possible paths there exists a return with the proper type. Even if you yourself can proof mathematically that the path Java complains about is never taken, the compiler might not be able to prove that the path is not possible at runtime. So you simply need to add an return there with a dummy value.
In your concrete example, there is a condition in which the loop gets never executed. If num <= 0, then the loop condition is never satified and the entire loop body is skipped. Without the return,the method is invalid, because you can't return nothing from an method with return type int.
So, in your example, the compiler is actually smarter then you, and prevents you from making a mistake - because it found the path you thought wouldn't occur.
new factors(-1).getFactors(); // you don't check the passed value at all ;)
From your comments, it seems that you want to return all factors. In java, you return once, and only once, from a function. This means you have to aggregate the results and return a List or array of values:
public List<Integer> getFactors(int num) {
List<Integer> factors = new ArrayList<>();
for (int i = 1 ; i<num ; i++)
{
if (num % i == 0)
{
factors.add(i);
}
}
return factors;
}
public static void main(String[] args) {
System.out.println(Arrays.toString(new factors(20).getFactors());
// prints a comma-separated list of all factors
}
does our return statement always have to be in the most outer indentation if you will?
No.
However, all potential code paths must return something. Consider this structure:
for(int i = 1 ; i<num ; i++)
{
if (num % i == 0)
{
return i;
}
}
What happens if num is a value where the loop itself is never entered? Or what happens if the if condition is never satisfied? No return statement would ever be encountered, which is invalid.
The compiler has to guarantee that the method will return something, under any and all potential runtime conditions. So while it's perfectly valid to return from within the loop, you also must provide logic for what to return if that return statement is never reached.
Java doesn't let you do that because what happens if the if (num % i == 0) is never true?
The methods return type is int, so it has to return an int. And it's possible that the if statement could be false, not every condition is covered with a return statement.
So if you wanted to you could return something like -1, or another invalid value. Then you know that the function didn't find what it was looking for.
I have a question about this block of Java code. (Yes, I am a beginner). The code works, I am just a little confused. This code checks the people and cars arrays to find if it has empty seats, which is what the tryToAdd method does. It will then add the person to that car. My question is about the boolean values. It looks to me that added is set to false. Then in the for loop it says: as long as added is true..do the loop. So, it seems that the loop should never run.
public void loadPassengers() {
for (Person p : people) {
boolean added = false;
for (int i = 0; !added && i < cars.size(); i++) {
added = cars.get(i).tryToAdd(p);
}
}
}
Then in the for loop it says: as long as added is true
Actually, it says the opposite of that. Look again:
for (int i = 0; !added && i < cars.size(); i++)
! is the 'logical inverse' (or not) operator. So this statement is actually saying 'stay in the for loop so long as we haven't added and i is less than the size of cars'.
Presumably, at some point cars.get(i).tryToAdd(p) will return true, and the for loop will terminate. Or you run out of cars. Either way the loop runs for at least one iteration (so long as you have at least one car).
You confused it. Actually,
if(!added)
{
//code
}
This condition is equal to:
if(added == false)
{
//code
}
So your logic says, as long as *added* is false, keep iterating, and try to perform' added = cars.get(i).tryToAdd(p); ,setting value of added to 'true'`
! is inverse of boolean.
You are executing a loop to say that unless a person is added (tryToAdd(p) which returns true) execute the loop. And also i < cars.size() says cars should have seat to add person.
Added explanation in your code.
public void loadPassengers() {
boolean added; //Declaring added variable outside for loop for memory management
for (Person p : people) { //Execute loop for each person
added = false; //setting added value to false for each person
// unless person is added execute the loop and also check for the car size.
for (int i = 0; (added == false && i < cars.size()); i++) { // added == false or !added is same
added = cars.get(i).tryToAdd(p); // tryToAdd(p) return true to confirm that a person is added
}
}
}