I have written a program to find the oldest and youngest person based on the ages and names that I have entered. The problem is, the program only gives me the oldest person, the else if statement for the youngest doesn't execute.
public class Boo {
public static void main(String[] strings) {
int[] age = new int[10];
String[] name = new String[10];
int count = 0;
Scanner in = new Scanner(System.in);
boolean notDone = true;
int smallest = age[0];
int largest = age[0];
String smalName = "";
String larName = "";
do {
System.out.println("Enter name");
name[count] = in.next();
if (!name[count].equalsIgnoreCase("done")) {
System.out.println("Enter age");
age[count] = in.nextInt();
if (age[count] > largest) {
largest = age[count];
larName = name[count];
}
else if (age[count] < smallest) {
smallest = age[count];
smalName = name[count];
}
}
else if (name[count].equalsIgnoreCase("done")) {
notDone = false;
}
count++;
}while(notDone && count < 3);
Your smallest variable is being instantiated to 0, because you set it to age[0], which being an array of integers has already been initialized to their default values of 0.
Try setting it to age[0] after you've first taken an age as an input, and then comparing subsequently.
int smallest = age[0];
int largest = age[0];
do
{
System.out.println("Enter name");
name[count] = in.next();
if (!name[count].equalsIgnoreCase("done"))
{
System.out.println("Enter age");
age[count] = in.nextInt();
if (count == 0)
{
smallest = age[0];
largest = age[0];
larName = name[0];
smalName = name[0];
}
else
{
if (age[count] > largest)
{
largest = age[count];
larName = name[count];
}
if (age[count] < smallest)
{
smallest = age[count];
smalName = name[count];
}
}
}
else if (name[count].equalsIgnoreCase("done"))
{
notDone = false;
}
count++;
} while (notDone && count < 3);
I would say it's best practice to separate it into 2 methods - one to get the youngest and on for the eldest. It will be clear to other developers who will might look at your code.
If that's not an option, you can use Pair in order to return two values. It meant to be for key and value but it enables you to return 2 values.
Your algorithm has some quirks that, maybe, you are not aware of. Your array age has been initialized by default. If you know what you are doing, it is not necessarily bad, but in this case it seems that you didn't. You are initializing the value of smallest and largest with values that are not in your list.
My advice is that you separate the recording of values from the computation of values.
EDIT: I mean something in this terms.
private class Person {
String name;
int age;
}
private Person enterPerson(Scanner sc) {
Person person = null;
String name = sc.next();
if(name != "done) {
int age = sc.nextInt();
person = new Person();
person.name = name;
person.age = age;
}
return person;
}
private Person youngest(List<Person> list) {
Person youngest = null;
for(Person person: list) {
if(youngest == null || youngest.age > person.age) {
youngest = person;
}
}
return person;
}
// Oldest would be equivalent
Related
Problem Statement: I have a 2D array of strings containing student names and respective marks as below
String[][] scores = {{"Bob","85"},{"Mark","100"},{"Charles","63"},{"Mark","34"}};
I want to calculate the best average among all the students available, i.e with the above input the best average should be 85.
My Attempt:
I tried to solve this using HashMap as below.
public int bestAverageCalculator(String[][] scores) {
// This HashMap maps student name to their list of scores
Map<String,List<Integer>> scoreMap = new HashMap<String,List<Integer>>();
for(String[] score:scores) {
String name = score[0];
int currentScore =Integer.parseInt(score[1]);
if(scoreMap.containsKey(name)) {
List<Integer> scoreList = scoreMap.get(name);
scoreList.add(currentScore);
scoreMap.put(name, scoreList);
}
else {
List<Integer> scoreList = new ArrayList<Integer>();
scoreList.add(currentScore);
scoreMap.put(name, scoreList);
}
}
//scoreMap will be {Charles=[63], Bob=[85], Mark=[100, 34]}
//After Map is formed i am iterating though all the values and finding the best average as below
int bestAverage = 0;
for(List<Integer> value:scoreMap.values()) {
int sum = 0;
int count = 0;
for(int i:value) {
sum+=i;
count++;
}
int average = (int)Math.floor(sum/count);
if(average>bestAverage)
bestAverage = average;
}
return bestAverage;// returns 85
}
The implementation is correct and i am getting the answer as expected, but i was told the space complexity of the program is more and it can be achieved without using the List<Integer> for marks, i am not able to understand how average can be calculated on fly without storing list of marks.
Please suggest if any other methods can solve this other than HashMap.
Any help would be appreciated.
You could store for each student a constant amount of data :
the student's name
the sum of all the student's marks
the number of the student's marks
This will make the space complexity O(m) where m is the number of unique students (instead of your O(n) where n is the number of marks).
For example, you can have a Student class with these 3 properties (and store the data in a List<Student>), or you can have a Map<String,int[]> with the key being the student's name and the value being an array of two elements containing the sum of the marks and the number of marks.
You can construct this data while iterating over the input.
Now you can compute the average for each student and find the highest average.
Well for space saving you can store two numbers per person
avgSum and count and calculate average on the end.
I have implemented #Eran 's approach based on your code with a Map<String,int[]> with
key: student's name
value: an array of two elements [the sum of the scores, the number of scores]
public int bestAverageCalculator(String[][] scores) {
// This HashMap maps student name to their total scores and count in an int array format of [totalScores, count]
Map<String,int[]> scoreMap = new HashMap<String,int[]>();
for(String[] score:scores) {
String name = score[0];
int currentScore =Integer.parseInt(score[1]);
if(scoreMap.containsKey(name)) {
int[] scoreCount = scoreMap.get(name);
scoreCount[0] += currentScore;
scoreCount[1] ++;
scoreMap.put(name, scoreCount);
}
else {
int[] scoreCount = new int[]{currentScore, 1};
scoreMap.put(name, scoreCount);
}
}
int bestAverage = 0;
for(int[] value:scoreMap.values()) {
int average = (int)Math.floor(value[0]/value[1]);
if(average>bestAverage)
bestAverage = average;
}
return bestAverage;// returns 85
}
#Eran's idea but with Student class, at least for me it's much more clear
import java.util.*;
public class Main {
static String[][] scores = {{"Bob", "85"}, {"Mark", "100"}, {"Charles", "63"}, {"Mark", "34"}};
public static void main(String[] args) {
List<Student> students = new ArrayList<>();
for (String[] score : scores) {
String name = score[0];
int currentScore = Integer.parseInt(score[1]);
Student student = findStudentByName(name, students);
if (student != null) {
student.setNumberOfScores(student.getNumberOfScores() + 1);
student.setSumOfScores(student.getSumOfScores() + currentScore);
} else {
student = new Student(name, 1, currentScore);
students.add(student);
}
}
findStudentWithBestAverage(students);
}
private static void findStudentWithBestAverage(List<Student> students) {
Student bestStudent = null;
int bestAverage = 0;
for (int i = 0; i < students.size(); i++) {
if ((students.get(i).getSumOfScores() / students.get(i).getNumberOfScores()) > bestAverage) {
bestStudent = students.get(i);
bestAverage = (students.get(i).getSumOfScores() / students.get(i).getNumberOfScores());
}
}
System.out.println(bestStudent + " with average: " + bestAverage);
}
private static Student findStudentByName(String name, List<Student> students) {
for (int i = 0; i < students.size(); i++) {
if (students.get(i).getName().equals(name)) {
return students.get(i);
}
}
return null;
}
public static class Student {
private String name;
private int numberOfScores;
private int sumOfScores;
public Student(String name, int numberOfScores, int sumOfScores) {
this.name = name;
this.numberOfScores = numberOfScores;
this.sumOfScores = sumOfScores;
}
public String getName() {
return name;
}
public int getNumberOfScores() {
return numberOfScores;
}
public void setNumberOfScores(int numberOfScores) {
this.numberOfScores = numberOfScores;
}
public int getSumOfScores() {
return sumOfScores;
}
public void setSumOfScores(int sumOfScores) {
this.sumOfScores = sumOfScores;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return name.equals(student.name);
}
#Override
public int hashCode() {
return Objects.hash(name);
}
#Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", numberOfScores=" + numberOfScores +
", sumOfScores=" + sumOfScores +
'}';
}
}
}
I have created an array of type Savings which contains a String (Name) and a double (Account Number). I want to search using an Account Number and see if it exist and then return all the elements (Name + Account Number) and the Index of the Array that contain these elements. I tried this but it does not work.
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args){
Savings[] ArrayOfSavings = new Savings[5];
System.out.print("Enter Account Number: ");
Scanner scan = new Scanner(System.in);
double Ms = scan.nextDouble();
//Loop until the length of the array
for(int index = 0; index<= ArrayOfSavings.length;index++){
if(ArrayOfSavings[index].equals(Ms)){
//Print the index of the string on an array
System.out.println("Found on index "+index);
}
}
ArrayOfSavings[0] = new Savings("Giorgos",87654321);
ArrayOfSavings[1] = new Savings("Panos",33667850);
}
}
/Savings Class/
public class Savings extends Generic {
public Savings(String FN, double AN) {
super(FN, AN);
}
#Override
public String toString(){
return String.format("Customer: %s \n Acount Number: %.1f,
getFirstName(),getAccNumber();
}
}
You could do something like this, where you return -1 if it doesn't exist, or the index if you've found it. Just have to make sure you check for this case.
public static int findSavingsIfExists(double accountNumber, Savings[] allSavings) {
for(int i = 0; i < allSavings.length(); i++) {
if(allSavings[i].accountNumber == accountNumber) {
return i;
}
}
return -1;
}
and use it like so
int index = findSavingsIfExists(..., ArrayOfSavings);
if(index != -1) {
Savings foundSavings = ArrayOfSavings[index];
} else {
//Not found
}
Try to use somethig like this:
double Ms = scan.nextDouble();
int index = 0;
for (int i = 0; i < ArrayOfSavings.length; i++) {
if (ArrayOfSavings[i].getAccountNumber == Ms ) {
index = i;
break;
}
}
System.out.println(index);
Trying to write a java code for a single row Battleship style game, and when I tried to convert from an array to an ArrayList, the game started returning "miss" no matter what.
public class SimpleDotComGame {
public static void main(String[] args) {
int numofGuess = 0;
Scanner sc = new Scanner(System.in);
SimpleDotCom dot = new SimpleDotCom();
int ranNum = (int) (Math.random() * 5);
ArrayList<Integer> locations = new ArrayList<Integer>();
locations.add(ranNum);
locations.add(ranNum + 1);
locations.add(ranNum + 2);
dot.setLocationCells(locations); //think like you're running a
// separate program with parameters to set cells as "locations"
boolean isAlive = true;
while (isAlive == true) {
System.out.println("Enter a number");
String userGuess = sc.next();
String result = dot.checkYourself(userGuess); //run program to
// check if cells were hit by userGuess
numofGuess++;
if (result.equals("kill")) {
isAlive = false;
System.out.println("You took " + numofGuess + " guesses");
}
}
sc.close();
}
}
public class SimpleDotCom {
int numofHits = 0;
ArrayList<Integer> locationCells;
public void setLocationCells(ArrayList<Integer> locations) { //locations
// variable described array so we must define it as array now
locationCells = locations;
}
public String checkYourself(String userGuess) { //check using parameter userGuess
int guess = Integer.parseInt(userGuess);
String result = "miss";
int index = locationCells.indexOf(userGuess);
if (index >= 0) {
locationCells.remove(index);
if (locationCells.isEmpty()) {
result = "kill";
} else {
result = "hit";
}
}
System.out.println(result);
return result;
}
}
Change :
int index = locationCells.indexOf(userGuess);
to
int index = locationCells.indexOf(guess);
userGuess is a String which can not possibly be in a list of Integers. guess is an int which can.
I have an object class
public class Film implements Comparable<Film>
I'm using Eclipse and would like to know why Film is underlined in red with the error saying:
The type Film must implement the inherited abstract method Comparable<Film>.compareTo<Film>
And now to my main question:
How would I get the max/min user submitted film length and title?
My object class Film has getter and setter methods for the Title of the film and the Length of the film and a toString method. Following this article (#3) I created two more methods in my object class:
public int max(Film maxLength){
int compareLength = ((Film) maxLength).getLength();
return this.length - compareLength;
}
public int min(Film minLength){
int compareLength = ((Film) minLength).getLength();
return compareLength - this.length;
}
Could I use these to find and print max/min values of the user submitted film lengths?
If so, how?
If not, what is the proper way of doing this?
The test class is as follows:
import java.util.Scanner;
public class test {
public static void main (String[] args){
Film[] f = new Film[3];
Scanner input = new Scanner(System.in);
for (int i=0;i<3;i++){
f[i] = new Film();
System.out.println("Enter Film Length:");
f[i].setLength(input.nextInt());
input.nextLine();
System.out.println("Enter Title:");
f[i].setTitle(input.nextLine());
}
input.close();
for (int i = 0; i < 3; i++) {
System.out.println(f[i].toString());
}
}
}
The Film class implements Comparable<Film>. What this means is that you must implement a method called compareTo() in class Film that will provide an ordering for objects of this class.
#Override
public int compareTo(Film that) {
// Order by film length
return Integer.compare(this.length, that.length);
}
If you only need to sort the objects by film length you can just use Arrays.sort():
Film[] films = new Film[3];
// put the objects into the array
Arrays.sort(films);
Then films[0] will contain the film with the shortest length, while the last element will be the film with the longest length.
If you need to compare by other fields, such as film title, you can create a custom comparator:
class FilmTitleComparator implements Comparator<Film> {
public int compare(Film a, Film b) {
return Integer.compare(a.getTitle().length(), b.getTitle().length());
}
}
And pass it to Arrays.sort()
FilmTitleComparator titleComparator = new FilmTitleComparator();
Arrays.sort(films, titleComparator);
Then films[0] will contain the film with the shortest title, while the last element will be the film with the longest title.
For simplicity, I stubbed your Film class to show a trivial example of how to implement Comparable
public class Film implements Comparable<Film> {
int maxLength;
int minLength;
String title;
public Film() {
this.maxLength = 0;
this.minLength = 0;
this.title = "";
}
// implement this method to accomplish comparison
public int compareTo(Film f) {
int result = 0; // the result to compute.
if ( this.equals(f) ) {
result = 0; // these objects are actually equal
}
// compare using meaningful data
else if ( f != null) {
// check to see if this film is greater than the specified film
if ( this.getMaxLength() > f.getMaxLength() ) {
// this film is comparatively greater, return > 0
result = 1;
}
else if ( this.getMaxLength() == f.getMaxLength() ) {
// these two films are comparatively equal
result = 0;
}
else {
// this film is comparatively less than the specified film
result = -1;
}
// similarly, you could also check min, but there's really no reason to do that unless your implementation calls for it.
}
else {
throw new IllegalArgumentException("null Film object not allowed here...");
}
return result;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Film film = (Film) o;
if (maxLength != film.maxLength) return false;
if (minLength != film.minLength) return false;
if (!title.equals(film.title)) return false;
return true;
}
#Override
public int hashCode() {
int result = maxLength;
result = 31 * result + minLength;
result = 31 * result + title.hashCode();
return result;
}
public int getMaxLength() {
return maxLength;
}
public void setMaxLength(int maxLength) {
this.maxLength = maxLength;
}
public int getMinLength() {
return minLength;
}
public void setMinLength(int minLength) {
this.minLength = minLength;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
To fix your test to actually use such an implementation (it doesn't really test anything...), you could do:
import java.util.Scanner;
public class test {
public static void main (String[] args){
Film lastFilm = null; // arbitrary reference to film
Film[] f = new Film[3];
Scanner input = new Scanner(System.in);
for (int i=0;i<3;i++){
f[i] = new Film();
System.out.println("Enter Film Length:");
f[i].setLength(input.nextInt());
input.nextLine();
System.out.println("Enter Title:");
f[i].setTitle(input.nextLine());
}
input.close();
for (int i = 0; i < 3; i++) {
if ( lastFilm != null ) {
// compare the films to test. current to last film
if ( f[i].compareTo(lastFilm) > 0 ) {
System.out.println(f[i].getTitle() + " is greater than " + lastFilm.getTitle()");
}
else if ( f[i].compareTo(lastFilm) < 0 ) {
System.out.println(f[i].getTitle() + " is less than " + lastFilm.getTitle()");
}
else {
System.out.println(f[i].getTitle() + " is equal to " + lastFilm.getTitle()");
}
}
System.out.println(f[i].toString());
lastFilm = f[i];
}
}
}
Something like this can get you started... good luck
Another solution would be to implement Comparable<Film>:
#Override
public int compareTo(Film that) {
return this.length - that.length;
}
And use org.apache.commons.lang3.ObjectUtils#min or org.apache.commons.lang3.ObjectUtils#max like:
Film min = ObjectUtils.min(film1, film2);
Film max = ObjectUtils.max(film1, film2);
Okay I cannot for the life of me figure out how to sort my data by tournament placings. Here is my code.
if (o == 5) {
double RD, t, old, x;
String tournament, player;
int a, number_of_players, place;
place = 0;
ArrayList<player> players = new ArrayList<player> ();
ArrayList<placeDisplay> placeVar = new ArrayList<placeDisplay> ();
List<placeDisplay> sort = new ArrayList<placeDisplay> ();
System.out.println("1:Add a tournament \t2:View Existing");
a = keyIn.nextInt();
if (a == 1) {
System.out.println("\nEnter tournament name");
tournament = keyIn.next();
System.out.println("\nEnter number of players");
number_of_players = keyIn.nextInt();
System.out.println("Enter players");
for (int i = 0; i < number_of_players; i++) {
String name = keyIn.next();
player plr = new player();
plr.setName(name);
players.add(plr);
}
System.out.println("\nEnter places for");
System.out.println(players);
for (int i = 0; i < players.size(); i++) {
System.out.println("\n" + players.get(i));
int places = keyIn.nextInt();
placeDisplay placer = new placeDisplay();
placer.setPlace(places);
placeVar.add(placer);
}
Collections.sort(sort);
System.out.println("\nThe Places are as follows");
for (int i = 0; i < players.size() && i < placeVar.size(); i++) {
System.out.println(placeVar.get(i) + ":" + players.get(i));
}
}
}
here is my public placeDisplay class file.
public class placeDisplay implements Comparable<placeDisplay> {
private int places;
public void setPlace(int nPlace) {
places = nPlace;
}
public int getPlace() {
return places;
}
#Override
public String toString() {
return Integer.toString(places);
}
#Override
public int compareTo(placeDisplay placeDisplay){
if (places > places)
return 1;
else if (places == places)
return 0;
else
return -1;
}
}
Here is the public class file
public class player {
private String name;
public void setName(String pName)
{
name = pName;
}
public String getName()
{
return name;
}
#Override
public String toString() {
return name;
}
}
and here is my result on this portion of the program. Hope you guys can help me out on this one!
1:Add a tournament 2:View Existing
1
Enter tournament name
tournament1
Enter number of players
3
Enter players
Bob
Sally
John
Enter places for
[Bob, Sally, John]
Bob
2
Sally
1
John
3
The Places are as follows
2:Bob
1:Sally
3:John
Return to Main Menu? (Y/N)
Need to Modify your comparator method.
public int compareTo(placeDisplay placeDisplay){
if (places > placeDisplay.places)
return 1;
else if (places == placeDisplay.places)
return 0;
else
return -1;
}
Your compareTo is not right because you are comparing the same variable.
Change it to:
#Override
public int compareTo(placeDisplay placeDisplay){
if (places > placeDisplay.getPlace())
return 1;
else if (places == placeDisplay.getPlace())
return 0;
else
return -1;
}
Or even simply:
#Override
public int compareTo(placeDisplay placeDisplay){
return places - placeDisplay.getPlace();
}
I also suggest you to overwrite the equals method to make it consistent with your compareTo, as recommended in the Comparable interface documentation: "The natural ordering for a class C is said to be consistent with equals if and only if e1.compareTo(e2) == 0 has the same boolean value as e1.equals(e2) for every e1 and e2 of class C. Note that null is not an instance of any class, and e.compareTo(null) should throw a NullPointerException even though e.equals(null) returns false.".