Finding item with the lowest cost in an ArrayList - java

What I need to do is find the inventory item with the lowest cost from an array list. If there are none, return "N/A". So I can't really figure out how to find the smallest value out of all the inventory item costs. This is what I have so far. My plan was to set cost equal to the first inventory item and cycle through each item checking if it's cost is less but I'm confused on how to do that or if that is even the correct way of doing it.
EDIT: We have not covered for loops yet so I cannot use them. I can only use while loops
public InventoryItem itemWithLowestCost() {
if (inventoryList.size() > 0) {
int i = 0;
while (i < inventoryList.size()) {
double cost = inventoryList.get(i).getCost();
if (cost < )
}
}
else {
return "N/A";
}
}
Here is my InventoryItem constructor. I'm not sure if this is needed to understand the above code but here it is anyway
public InventoryItem(String descriptionIn, double costIn, double percentDepreciatedIn) {
description = descriptionIn.trim();
cost = costIn;
percentDepreciated = percentDepreciatedIn;
}

You can do it by checking the length to be non-zero, then picking the cost of element zero as "tentative best", and comparing it to costs of other elements on the list:
if (inventoryList.size() > 0) {
int best = 0;
int i = 1;
while (i < inventoryList.size()) {
double cost = inventoryList.get(i).getCost();
if (cost < inventoryList.get(best).getCost()) {
best = i;
}
i++;
}
return inventoryList.get(best);
} else {
return "N/A";
}

You can do it with a O(n) loop
public InventoryItem itemWithLowestCost() {
int size = (inventoryList == null || inventoryList.isEmpty()) ?
0 : inventoryList.size();
InventoryItem min = (size > 0) ? inventoryList.get(0) : null;
for (int i = 1; i < size; i++) {
InventoryItem ii = inventoryList.get(i);
if (ii.getCost() < min.getCost()) min = ii;
}
return min;
}
Note: That you can't return a String N/A as an InventoryItem instance (so this returns null).

You could use a comparitor to sort the inventory by cost, lowest to highets.
public InventoryItem itemWithLowestCost(Collection<InventoryItem> inventory) {
if(inventory != null && !inventory.isEmpty()) {
Collections.sort(inventory, new Comparator<InventoryItem>() {
#Override
public int compare(InventoryItem i1, InventoryItem i2) {
return i1.getCost() - i2.getCost();
}
});
return inventory.get(0);
}
return null;
}

Related

Bubble Sort objects

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]

java method find max price

My findmaxprice method returns the index of the first Car in the array with the maximum price. If it is not found, -1 is returned.
As far as I know, return will stop the for loop. Any advice on how to avoid it while keep the loop search for max price?
public int findmaxprice() {
double max =0;
for(int i =0; i < nCars; i++) {
if(max <= Cars[i].getPrice()) {
max = Cars[i].getPrice();
return i; //the problem is here
}
}
return -1;
}
You almost answered yourself - just don't return in the for loop.
public int findmaxprice() {
double max =0;
int maxIndex = -1;
for( int i =0; i < nCars; i++) {
if(max <= Cars[i].getPrice()) {
max = Cars[i].getPrice();
maxIndex = i;
}
}
return maxIndex;
}
Move the return statement outside of the loop
findmaxprice method: returns the index of the first Car in the array with the maximum price. If it is not found, -1 is returned. as far as i know, return will stop the for loop , any advice on how to avoid it while keep the loop search for max price ?
public int findmaxprice() {
double max =0;
for( int i =0; i < nCars; i++) {
if(max <= Cars[i].getPrice()) {
max = Cars[i].getPrice();
}
}
if(max != 0){
return max;
} else {
return -1;
}
}
The below method will fix your issue. Also, it gives you ability to specify a minimum price above which the car price will be considered for max calculation. You can keep this 0 in function call like findMaxPrice(0)if no such boundation needed.
public int findMaxPrice(int min) {
double max = min;
int maxPriceCarIndex = -1;
for (int i = 0; i < nCars; i++) {
if (max <= Cars[i].getPrice()) {
max = Cars[i].getPrice();
maxPriceCarIndex = i; //reassign the index here
}
}
return maxPriceCarIndex;
}
Maybe you just need the "most expensive" car and not the index of the car, then you could consider using streams
import java.util.Arrays;
import java.util.Comparator;
import java.util.Objects;
public class Test {
public static void main(String[] args) {
new Test().testGetMostExpensiveCar();
}
private void testGetMostExpensiveCar() {
// test null array
Car[] cars = null;
Car mostExpensive = getMostExpensiveCar(cars);
System.out.println(mostExpensive); // prints null
// test empty array
cars = new Car[10];
mostExpensive = getMostExpensiveCar(cars);
System.out.println(mostExpensive); // prints null
//test array with cars
cars[0] = new Car(10.0);
cars[5] = new Car(20.0);
cars[8] = new Car(30.0);
cars[8] = new Car(30.0);
mostExpensive = getMostExpensiveCar(cars);
System.out.println(mostExpensive);// prints Car [price=30.0]
}
/**
* #param cars
* #return the most Expensive car, null if the array is empty or no car is in
* the array
*/
public Car getMostExpensiveCar(Car[] cars) {
if (cars == null) {
return null;
}
return Arrays.stream(cars) // creates a Stream<Car> (take a look at e.g. https://www.baeldung.com/java-8-streams)
.filter(Objects::nonNull) // because there can be "null" values in the array
.max(Comparator.comparing(Car::getPrice)) // compares the car by price asc
.orElse(null); // return null if no element is found
}
private class Car {
private double price;
public Car(double price) {
super();
this.price = price;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
#Override
public String toString() {
return "Car [price=" + price + "]";
}
}
}

Overriding the add method for ArrayList<Integer>

Question: I am trying to override the add method of ArrayList to remember the last three digits added to the arraylist. I am to then take these three values and find the maximum value among them.
It seems that I can not get my add method to save the three elements without an out of bounds error.
import java.util.ArrayList;
public class MaxThreeArrayList extends ArrayList<Integer> {
MaxThreeArrayList maxlist = new MaxThreeArrayList();
int third_last = 0;
int second_last = 0;
int last = 0;
#Override public boolean add(Integer o){
if (maxlist.size() == 1){
last = maxlist.get(maxlist.size() - 1);
}
else if (maxlist.size() == 2){
last = maxlist.get(maxlist.size() - 1);
second_last = maxlist.get(maxlist.size() - 2);
}
else if (maxlist.size() >= 3){
last = maxlist.get(maxlist.size() - 1);
second_last = maxlist.get(maxlist.size() - 2);
third_last = maxlist.get(maxlist.size() - 3);
}
return super.add(o);
}
public int getMax(){
int maximum = 0;
if (third_last >= second_last){
if (third_last >= last){
maximum = third_last;
}
}
if (second_last >= third_last){
if (second_last >= last){
maximum = second_last;
}
}
if (last >= second_last){
if (last >= third_last){
maximum = last;
}
}
return maximum;
}
public static void main(String[] args) {
}
}
I think you should separate your concerns. Your overridden add should only worry about remembering the last three things you add to the list. This can be accomplished pretty easy with a deque. The method getMax should figure out which one is the largest, as its name suggests.
public class MaxThreeArrayList extends ArrayList<Integer> {
private final Deque<Integer> deque = new LinkedList<>();
#Override public boolean add(Integer i) {
deque.addFirst(i);
if (deque.size() > 3) { deque.removeLast(); }
return super.add(i);
}
public Integer getMax() {
Integer max = 0;
for (Integer i : deque) {
if (i > max) { max = i; }
}
return max;
}
}
As an additional exercise, you may note that this code can be made more general. It doesn't need to be hard-coded to remember the last 3. You could make that number configurable.

Java returns woes

Okay so I have the following code and no matter what it returns to me a -1. I want to have it so that if the id matches then it returns and index but if it doesn't match after running through the whole data set it returns a negative one. Where am I going wrong here:
public class StudentCollection {
private String[] ids = new String[] {"Empty","Empty","Empty","Empty","Empty","Empty","Empty","Empty","Empty","Empty","Empty","Empty","Empty","Empty","Empty","Empty","Empty","Empty","Empty","Empty"}; // keeps identification numbers of students
private String [] names = new String[] {"Empty","Empty","Empty","Empty","Empty","Empty","Empty","Empty","Empty","Empty","Empty","Empty","Empty","Empty","Empty","Empty","Empty","Empty","Empty","Empty"};; // keeps the names of students
private int size = 0; // number of students currently in the collection
private int findIndex(String id) {
int noIndex = 1;
for (int i=0;i<ids.length;i++){
if((ids[i].equalsIgnoreCase(id))){
System.out.println("The index of this student is " +i);
}
else {
noIndex = -1;
System.out.println(noIndex);
break;}
}
return noIndex;
}
Here is the solution where if index is found then its number is returned, else if it isn't after checking whole array, -1 is returned and appropriate Strings are printed.
private int findIndex(String id) {
int noIndex = -1;
for (int i = 0; i < ids.length; i++) {
if (ids[i].equalsIgnoreCase(id)) {
System.out.println("The index of this student is " + i);
return i;
}
}
System.out.println(noIndex);
return noIndex;
}
You can also use Java 8 Stream:
private int findIndex(String id) {
OptionalInt index = IntStream.rangeClosed(0, ids.length-1)
.filter(i -> ids[i].equalsIgnoreCase(id))
.findFirst();
if(index.isPresent()) {
int i = index.getAsInt();
System.out.println("The index of this student is " + i);
return i;
}
System.out.println(-1);
return -1;
}
Right now you have it so when ids[i].equalsIgnoreCase(id)is true, it will set noIndexto -1 (in the else statement) and break the for loop which will make it return -1. When that is false, it will print out the index.
Like everyone else has already posted, here is the code to find the index.
private int findIndex(String id) {
for (int i=0;i<ids.length;i++){
if(ids[i].equalsIgnoreCase(id)){
return i;
}
}
return -1;
}
i think you need something like this :
private int findIndex(String id) {
for (int i=0; i<ids.length; i++){
if(ids[i].equalsIgnoreCase(id)){
System.out.println("The index of this student is " +i);
return i;
}
}
return -1;
}

java programming & finding the mode of an array

i have a task where i need to find the mode of an array. which means i am looking for the int which is most frequent. i have kinda finished that, but the task also says if there are two modes which is the same, i should return the smallest int e.g {1,1,1,2,2,2} should give 1 (like in my file which i use that array and it gives 2)
public class theMode
{
public theMode()
{
int[] testingArray = new int[] {1,1,1,2,2,2,4};
int mode=findMode(testingArray);
System.out.println(mode);
}
public int findMode(int[] testingArray)
{
int modeWeAreLookingFor = 0;
int frequencyOfMode = 0;
for (int i = 0; i < testingArray.length; i++)
{
int currentIndexOfArray = testingArray[i];
int frequencyOfEachInArray = howMany(testingArray,currentIndexOfArray);
if (frequencyOfEachInArray > frequencyOfMode)
{
modeWeAreLookingFor = currentIndexOfArray;
frequencyOfMode = modeWeAreLookingFor;
}
}
return modeWeAreLookingFor;
}
public int howMany(int[] testingArray, int c)
{
int howManyOfThisInt=0;
for(int i=0; i < testingArray.length;i++)
{
if(testingArray[i]==c){
howManyOfThisInt++;
}
}
return howManyOfThisInt;
}
public static void main(String[] args)
{
new theMode();
}
}
as you see my algorithm returns the last found mode or how i should explain it.
I'd approach it differently. Using a map you could use each unique number as the key and then the count as the value. step through the array and for each number found, check the map to see if there is a key with that value. If one is found increment its value by 1, otherwise create a new entry with the value of 1.
Then you can check the value of each map entry to see which has the highest count. If the current key has a higher count than the previous key, then it is the "current" answer. But you have the possibility of keys with similar counts so you need to store each 'winnning' answer.
One way to approach this is to check each map each entry and remove each entry that is less than the current highest count. What you will be left with is a map of all "highest counts". If you map has only one entry, then it's key is the answer, otherwise you will need to compare the set of keys to determine the lowest.
Hint: You're updating ModeWeAreLookingFor when you find a integer with a strictly higher frequency. What if you find an integer that has the same frequency as ModeWeAreLookingFor ?
Extra exercice: In the first iteration of the main loop execution, you compute the frequency of '1'. On the second iteration (and the third, and the fourth), you re-compute this value. You may save some time if you store the result of the first computation. Could be done with a Map.
Java code convention states that method names and variable name should start with a lower case character. You would have a better syntax coloring and code easier to read if you follow this convention.
this might work with a little modification.
http://www.toves.org/books/java/ch19-array/index.html#fig2
if ((count > maxCount) || (count == maxCount && nums[i] < maxValue)) {
maxValue = nums[i];
maxCount = count;
}
since it seems there are no other way, i did a hashmap after all. i am stuck once again in the logics when it comes to comparing frequencys and and the same time picking lowest integer if equal frequencys.
public void theMode()
{
for (Integer number: intAndFrequencyMap.keySet())
{
int key = number;
int value = intAndFrequencyMap.get(number);
System.out.println("the integer: " +key + " exists " + value + " time(s).");
int lowestIntegerOfArray = 0;
int highestFrequencyOfArray = 0;
int theInteger = 0;
int theModeWanted = 0;
if (value > highestFrequencyOfArray)
{
highestFrequencyOfArray = value;
theInteger = number;
}
else if (value == highestFrequencyOfArray)
{
if (number < theInteger)
{
number = theInteger;
}
else if (number > theInteger)
{
}
else if (number == theInteger)
{
number = theInteger;
}
}
}
}
Completed:
import java.util.Arrays;
public class TheMode
{
//Probably not the most effective solution, but works without hashmap
//or any sorting algorithms
public TheMode()
{
int[] testingArray = new int[] {2,3,5,4,2,3,3,3};
int mode = findMode(testingArray);
System.out.println(Arrays.toString(testingArray));
System.out.println("The lowest mode is: " + mode);
int[] test2 = new int[] {3,3,2,2,1};
int mode2=findMode(test2);
System.out.println(Arrays.toString(test2));
System.out.println("The lowest mode is: " +mode2);
int[] test3 = new int[] {4,4,5,5,1};
int mode3 = findMode(test3);
System.out.println(Arrays.toString(test3));
System.out.println(The lowest mode is: " +mode3);
}
public int findMode(int[] testingArray)
{
int modeWeAreLookingFor = 0;
int frequencyOfMode = 0;
for (int i = 0; i < testingArray.length; i++)
{
int currentIndexOfArray = testingArray[i];
int countIntegerInArray = howMany(testingArray, currentIndexOfArray);
if (countIntegerInArray == frequencyOfMode)
{
if (modeWeAreLookingFor > currentIndexOfArray)
{
modeWeAreLookingFor = currentIndexOfArray;
}
}
else if (countIntegerInArray > frequencyOfMode)
{
modeWeAreLookingFor = currentIndexOfArray;
frequencyOfMode = countIntegerInArray;
}
}
return modeWeAreLookingFor;
}
public int howMany(int[] testingArray, int c)
{
int howManyOfThisInt=0;
for(int i=0; i < testingArray.length;i++)
{
if(testingArray[i]==c){
howManyOfThisInt++;
}
}
return howManyOfThisInt;
}
public static void main(String[] args)
{
new TheMode();
}
}
Glad you managed to solve it. As you will now see, there is more than one way to approach a problem. Here's what I meant by using a map
package util;
import java.util.HashMap;
import java.util.Map;
public class MathUtil {
public static void main(String[] args) {
MathUtil app = new MathUtil();
int[] numbers = {1, 1, 1, 2, 2, 2, 3, 4};
System.out.println(app.getMode(numbers));
}
public int getMode(int[] numbers) {
int mode = 0;
Map<Integer, Integer> numberMap = getFrequencyMap(numbers);
int highestCount = 0;
for (int number : numberMap.keySet()) {
int currentCount = numberMap.get(number);
if (currentCount > highestCount) {
highestCount = currentCount;
mode = number;
} else if (currentCount == highestCount && number < mode) {
mode = number;
}
}
return mode;
}
private Map<Integer,Integer> getFrequencyMap(int[] numbers){
Map<Integer, Integer> numberMap = new HashMap<Integer, Integer>();
for (int number : numbers) {
if (numberMap.containsKey(number)) {
int count = numberMap.get(number);
count++;
numberMap.put(number, count);
} else {
numberMap.put(number, 1);
}
}
return numberMap;
}
}

Categories