Altering variables inside ArrayList with double for loop - java

I have an ArrayList called participatingUsers. Person has Person.money and Person.name that are interesting.
What I want to do is check the ArrayList against itself...
So I have this code
for (Person debtHaver : this.participatingUsers) {
// If they're in debt...
if (debtHaver.getMoney() < 0) {
// With someone...
for (Person personToPay : this.participatingUsers) {
// That's not themselves...
if (!debtHaver.getName().equals(personToPay.getName())) {
// See if the personToPay is ranked higher than the
// debtHaver...
if (personToPay.getMoney() > 0) {
// If the debtee can pay the debter in full
if (-debtHaver.getMoney() <= personToPay.getMoney()) {
payment += debtHaver.getName() + " has to pay " + personToPay.getName() + " " + -debtHaver.getMoney() + "\n";
debtHaver.increaseMoney(-debtHaver.getMoney());
personToPay.decreaseMoney(-debtHaver.getMoney());
}
if (-debtHaver.getMoney() > personToPay.getMoney())
{
//But if he can't pay in full... Just pay the small bit you can pay.
payment += debtHaver.getName() + " has to pay " + personToPay.getName() + " " + personToPay.getMoney() + "\n";
debtHaver.increaseMoney(personToPay.getMoney());
personToPay.decreaseMoney(personToPay.getMoney());
}
}
}
}
}
}
return payment;
Basically, I have a double for loop where I check each person against itself. If someone is in debt and has a negative amount of money, seek if there is someone who they can pay, then pay that person. The thing is, personToPay is not being updated in the arrayList debtHaver is in. I'm basically editing two different ArrayLists instead of the same one. What's the best way to deal with this issue?

You are editing the same list. The problem is probably in this code:
debtHaver.increaseMoney(-debtHaver.getMoney());
personToPay.decreaseMoney(-debtHaver.getMoney());
You are putting debtHaver's amount to zero by the first line. And then you try to modify personToPay with zero amount. Just swap two lines of code and it should work:
personToPay.decreaseMoney(-debtHaver.getMoney());
debtHaver.increaseMoney(-debtHaver.getMoney());

Related

How to add an object during ListIterator (reversed) iteration properly?

I have been asked from my professor to add an object in the middle of an ArrayedList<Employee> using listiterator.
I have tried doing in the following way first:
ListIterator < Employee > li = emps.listIterator(emps.size());
System.out.println("\nUsing ListIterator:\n");
i = 1;
while (li.hasPrevious()) {
if (li.nextIndex() == 5) {
li.add(emp_M);
}
System.out.println(" Employee " + (i++) + " " + li.previous());
}
But this produces a seemingly infinite number of iterations where li.nextIndex() gets stuck on 5.
I have verified this with the debugger and this happens only after li.add(emp_M) is evaluated.
I have found a solution where I added a break right after li.add(emp_M) and continued parsing the list separately in the same way but without adding to the list emp_M at all:
//parse in two loops to add the middle employee, without the break the list seemingly spirals into infinity!
System.out.println("\nUsing ListIterator:\n");
i = 1;
while (li.hasPrevious()) {
if (li.nextIndex() == 5) {
li.add(emp_M);
System.out.println("ADDED IN MIDDLE");
break;
}
System.out.println(" Employee " + (i++) + " " + li.previous());
}
while (li.hasPrevious()) {
System.out.println(" Employee " + (i++) + " " + li.previous());
}
This left me wondering, is what I did a lazy and naive approach? How else can I add to a list with listIterator?
The problem in your code is that you will add the element emp_M indefinitely.
If we go through one iteration where you add an element:
Suppose li.nextIndex() == 5, then you will add a new element to your iterator, and according to the documentation of add, you will also increase by one your index (hence you move your iterator to the right). Then your loops continues and you move your iterator to the left with li.previous(), which happens to be place before you added the element (and verifies the if condition to add).
Now, you start a new iteration of your while loop, verifies the condition again, add a new element ect... You will stay stuck at the element verifying the condition by adding indefinitely new elements.
To make the code easier, try to run your iterator in the documentation direction (ie e1 -> e2 -> e3 -> e4)
ListIterator < Employee > li = emps.listIterator();
i = 1;
while (li.hasNext()) {
if (li.nextIndex() == 5) {
li.add(emp_M);
}
System.out.println(" Employee " + (i++) + " " + li.next());
}
I have found it after digging deeper in the debugger.
At the moment before adding li.nextIndex() == 5 and li.previousIndex() == 4
After adding the object the aforementioned change to li.nextIndex() == 6 and li.previousIndex() == 5 this is because listIterator's .add() inserts the object before .next().
Moving ahead with this problem sets up a back and forth loop where li.previous() decreases both li.previousIndex() and li.nextIndex() by 1, and calling li.add(emp_M) increases both aforementioned values by 1.
To fix it, we need to skip the added element after adding:
System.out.println("\nUsing ListIterator:\n");
i = 1;
while (li.hasPrevious())
{
if(li.nextIndex() == 5)
{
li.add(emp_M);
li.previous();
System.out.println("ADDED IN MIDDLE");
// break;
}
System.out.println(" Employee " + (i++) + " " + li.previous());
}
this effectively negates the problem mentioned above.
Sometimes by simply asking a question you find the answer yourself!
I'm going to delay accepting my own answer if someone can explain it to me better than I understood it.

Java 8: No errors - Why is this for loop running forever and not showing anything?

My issue is with the following code. Eclipse IDE gives me no errors or warnings, yet when I print out a simple System.out.println("Test" + i);, I would get a running program up to the number 2509, or currently 2517 after rebooting Eclipse.
Essentially, I want to take an array of objects, say an array of "persons," and place them in random spots in another object array, say "bus stops." Assume that I have properly made the object arrays for "busStops and "people"
Yes, I realize that it defeats the purpose of making the "person" object as of yet, but that is something that can be included later.
Edit: Null values are simulated areas where people can't go, like a lake.
Edit2: replaced for with while loop, replaced decremented i with continue keyword.
Edit3: added more of the methods to elaborate the imperfections of my code. Then again, maybe most of it is good and I'm not understanding something important about loops.
private static void distributePeople() {
boolean temp = true;
int i = 0;
while (temp) {
// Select random points in array
int a = rand.nextInt(busStops.length);
int b = rand.nextInt(busStops[0].length);
// At random busStop, check if available and check if not full.
// If it is not full, place a person there.
if (busStops[a][b] == null) {
// if null, reset this run
continue;
} else {
if (busStops[a][b].isMaxPeople() == false) {
busStops[a][b].setNumberOfPeople(1);
i++;
System.out.println("Test: " + i);
} else {
// if true, reset this run
continue;
}
}
if (i == people.length) {
temp = false;
}
}
}
private static void setMaxPeopleAtBusStop() {
busStops[0][0].setMaxNumberOfPeople(1977 + 2);
busStops[1][0].setMaxNumberOfPeople(2 + 1643);
busStops[2][0].setMaxNumberOfPeople(1643 + 1201);
busStops[3][0].setMaxNumberOfPeople(1201 + 1267);
busStops[0][1].setMaxNumberOfPeople(366 + 0);
busStops[2][1].setMaxNumberOfPeople(0 + 797);
busStops[3][1].setMaxNumberOfPeople(797 + 34);
busStops[0][2].setMaxNumberOfPeople(1740 + 0);
busStops[2][2].setMaxNumberOfPeople(0 + 1444);
busStops[3][2].setMaxNumberOfPeople(1444 + 1963);
busStops[0][3].setMaxNumberOfPeople(839 + 1131);
busStops[1][3].setMaxNumberOfPeople(1131 + 1092);
busStops[2][3].setMaxNumberOfPeople(1092 + 912);
busStops[3][3].setMaxNumberOfPeople(912 + 1965);
busStops[0][4].setMaxNumberOfPeople(1552 + 1297);
busStops[1][4].setMaxNumberOfPeople(1297 + 1345);
busStops[2][4].setMaxNumberOfPeople(1345 + 614);
busStops[3][4].setMaxNumberOfPeople(614 + 1108);
busStops[0][5].setMaxNumberOfPeople(1490 + 228);
busStops[1][5].setMaxNumberOfPeople(228 + 187);
busStops[2][5].setMaxNumberOfPeople(187 + 906);
busStops[3][5].setMaxNumberOfPeople(906 + 36);
busStops[0][6].setMaxNumberOfPeople(634 + 1293);
busStops[1][6].setMaxNumberOfPeople(1293 + 0);
busStops[3][6].setMaxNumberOfPeople(0 + 1929);
busStops[0][7].setMaxNumberOfPeople(759 + 388);
busStops[1][7].setMaxNumberOfPeople(388 + 0);
busStops[3][7].setMaxNumberOfPeople(0 + 1149);
busStops[0][8].setMaxNumberOfPeople(1809 + 1880);
busStops[1][8].setMaxNumberOfPeople(1880 + 1979);
busStops[2][8].setMaxNumberOfPeople(1979 + 954);
busStops[3][8].setMaxNumberOfPeople(954 + 1332);
busStops[0][9].setMaxNumberOfPeople(1890 + 408);
busStops[1][9].setMaxNumberOfPeople(408 + 1771);
busStops[2][9].setMaxNumberOfPeople(1771 + 587);
busStops[3][9].setMaxNumberOfPeople(557 + 1961);
}
From the appropriate BusStop class:
static int MAX_PEOPLE_HERE;
public int setNumberOfPeople(int a) {
return numberOfPeopleHere += a;
}
protected boolean isMaxPeople() {
if (numberOfPeopleHere >= MAX_PEOPLE_HERE) {
return true;
} else {
return false;
}
}
public void setMaxNumberOfPeople(int a) {
MAX_PEOPLE_HERE = a;
}
Note: I should have a max number of 13000 people, which is smaller than the room available above.
Ok so your problem is that you're using a static variable for MAX_PEOPLE_HERE but you're trying to use it in a non static way. Thus ever time you call setMaxNumberOfPeople on any bus stop you set it for all bus stops.
This means that MAX_PEOPLE_HERE will end up being 557 + 1961 = 2518.
I'm guessing that numberOfPeopleHere is also static and thus you can only ever 2518 people to bus stops. If you try to do more than this then you'll end up with an infinite loop as you are seeing.
Change both MAX_PEOPLE_HERE (rename this to maxPeopleHere) and numberOfPeopleHere to local instance variables and I suspect everything will start working.
Use continue instead of i-- to skip current iteration. As #Hovercraft Full Of Eels stated, you've got infinite loop because of index modification within the loop

Set term factors dynamically from an imported cplex-Model

Let's say i have an OptimizationModel abc.lp, which i want to import with the CPlex java-API. I use: importModel function (click) to import it. Now i want to change some decision variable's factors in the constraint or in the objective. For example the imported model abc.lp looks as follows:
Objective: Minimize <factor1>x1 + <factor2>x2
Constraint: <factor1>x1 + <factor2>x2 <= 40
For me factor1 and factor2 are input parameters of a function. So i get:
public void(double factor1, double factor2){
...
cplexModel.import("path/to/abc.lp")
// Change parameters, how to do it?
Is there a handy way to set the factors dynamically from an imported Model with the Cplex-API?
Thanks a lot!
Yes, this is possible. It's not very intuitive, at least to me.
Here's an example snippet that assumes a LP (linear objective and constraints):
// Read model from file with name args[0] into cplex optimizer object
cplex.importModel(args[0]);
// Get the objective and modify it.
IloObjective obj = cplex.getObjective();
IloLinearNumExpr objExpr = (IloLinearNumExpr) obj.getExpr();
IloLinearNumExprIterator iter = objExpr.linearIterator();
// Loop through the linear objective and modify, as necessary.
while (iter.hasNext()) {
IloNumVar var = iter.nextNumVar();
System.out.println("Old coefficient for " + var + ": " + iter.getValue());
// Modify as needed.
if ( var.getName().equals("x1") ) {
iter.setValue(42);
System.out.println("New coefficient for " + var + ": " + iter.getValue());
}
}
// Save the changes.
obj.setExpr(objExpr);
// Assumes that there is an LP Matrix. The fact that we used
// importModel() above guarantees that there will be at least
// one.
IloLPMatrix lp = (IloLPMatrix) cplex.LPMatrixIterator().next();
for (int i = 0; i < lp.getNrows(); i++) {
IloRange range = lp.getRange(i);
System.out.println("Constraint " + range.getName());
IloLinearNumExpr conExpr = (IloLinearNumExpr) range.getExpr();
IloLinearNumExprIterator conIter = conExpr.linearIterator();
// Loop through the linear constraints and modify, as necessary.
while (conIter.hasNext()) {
IloNumVar var = conIter.nextNumVar();
System.out.println("Coefficient for " + var + ": " + conIter.getValue());
// Modify as needed (as above).
if ( var.getName().equals("x1") ) {
conIter.setValue(42);
System.out.println("New coefficient for " + var + ": " + conIter.getValue());
}
}
// Save changes (as above).
range.setExpr(conExpr);
}
cplex.exportModel("modified.lp");
// Solve the model and display the solution if one was found
if ( cplex.solve() ) {
// do something here.
}
Here, we're looking for a variable named "x1". We set it's coefficient to 42 in the objective and in all linear constraints. The println's are for debugging. I did this quickly, so make sure you test it. Otherwise, you should be able to modify that to suit your needs. Hope that helps.

Can't remember how to do this for some reason

This one should be fairly simple I think, I just can't remember how, when using get methods of an object, how to pull the highest double out of the pack and put it in the println.
So far I just get every object to print with its percentages. But for the life of me I just can't remember and I know I've done this before.
public void displayBookWithBiggestPercentageMarkup(){
Collection<Book> books = getCollectionOfItems();
Iterator<Book> it = books.iterator();
while(it.hasNext()){
Book b = it.next();
double percent = b.getSuggestedRetailPriceDollars() / b.getManufacturingPriceDollars() * 100.0;
System.out.println("Highest markup is " + percent + " " + b.getTitle() + " " + b.getAuthor().getName().getLastName());
}
}
I'm pretty sure I need another local variable but I can't seem to do anything but make it equal the other percent. I have removed the other variable for now as I try to think about it.
I won't go into a lot of detail because it's homework (well done for being up-front about that, by the way) but here's the key idea: keep track of the largest percentage you've seen so far as your loop runs. That's what you want in your other variable.
Good job posting what you've tried so far. You were on the right track. As you loop through your books, keep a variables continuously updated with the highest percent seen so far and another variable for the associated book. Output the variable at the end outside the loop after iteration is done. Also, don't forget to check the edge case of an empty list of books! Something like this should do the trick:
public void displayBookWithBiggestPercentageMarkup(){
Collection<Book> books = getCollectionOfItems();
if (books.size() == 0) {
return;
}
Iterator<Book> it = books.iterator();
double highestPercent = 0;
Book highestPercentBook = null;
while(it.hasNext()){
Book b = it.next();
double percent = b.getSuggestedRetailPriceDollars() / b.getManufacturingPriceDollars() * 100.0;
if (percent > highestPercent) {
highestPercent = percent;
highestPercentBook = b;
}
}
System.out.println("Highest markup is " + highestPercent
+ " " + highestPercentBook.getTitle()
+ " " + highestPercentBook.getAuthor().getName().getLastName());
}

What am I doing wrong here? if statements not adding up

total in this case is 500. Trying to make a calculator, but not everything's adding up. It seems to skip the multiplication and just display total*amount. Is there something I'm doing wrong? EDIT: Discount: in the example, .92. I get 455000 if amount is 1000.
if (wShipping==true){
if (GroundShipping.isSelected()){
if (amount<=99) {
shipping=1.05;
output.setText(output.getText() + amount + "\t" + total*1.05*amount*discount + "\n");
}
else{
output.setText(output.getText() + amount + "\t" + total*amount*discount + "\n");
}
}
if (AirShipping.isSelected()){
shipping=1.1;
output.setText(output.getText() + amount + "\t" + total*amount*1.1*discount + "\n");
}
if (FedexShipping.isSelected()){
shipping=1.25;
output.setText(output.getText() + amount + "\t" + (total*amount*discount)*(1.25) + "\n");
}
}
You should consider the following things--
1) Why is the variable shipping needed if you are directly using the value in the set statement
2) Use else if statement since all the options are exclusive
3) You might want to check the initial values for variables and the formula for calculating the price. Taking the initial values as given, the lowest possible price is-
Price = 1000*500*0.92 = 460000 (total x amount x discount)
Hence there must be something amiss with your initial values
Maybe, just maybe is the first rule of currency calculations:
why not use double or float to represent currency

Categories