My hashmap contains a key which is the customers name, and the values are all the ratings for the books rated. I have to calculate the average rating for a given booktitle.
How do I access all of the values (ratings) from the hashmap? Is there a method for doing this?
Here is a piece of my code:
/**
* calculate the average rating by all customers for a named book
* only count positive or negative ratings, not 0 (unrated)
* if the booktitle is not found or their are no ratings then
* return NO_AVERAGE
* #param booktitle String to be rated
* #return double the average of all ratings for this book
*/
public double averageRating(String booktitle)
{
numberOfRatingsPerCustomer/total
}
You need to get the keySet from the HashMap. And then Iterate over the keySet and fetch the values from the HashMap.
Your question makes no sense.
You can't have a map with customerName to hisRatingOfBook, and search in it for bookTitle. You need to go one of 1 ways:
1)
create method public double averageRating() inside Book class, and keep there, as field, rating being map with customerName to hisRatingOfBook
2) Use your method:
public double averageRating(String booktitle)
{
numberOfRatingsPerCustomer/total
}
but make your map something more complex, that will hold customer, and its rating (being made from book title + rate)
Here you go take these below code it will help you out to find your rating problem
I have done to find average of Student marks in a class
import java.util.*;
public class QueQue {
public static float getAverage(HashMap<String, ArrayList<Integer>> hm, String name) {
ArrayList<Integer> scores;
scores = hm.get(name);
if (scores == null) {
System.out.println("NOT found");
}
int sum = 0;
for (int x : scores) {
sum += x;
}
return (float) sum / scores.size();
}
public static void main(String[] args) {
HashMap<String, ArrayList<Integer>> hm = new HashMap<>();
hm.put("Peter", new ArrayList<>());
hm.get("Peter").add(10);
hm.get("Peter").add(10);
hm.get("Peter").add(10);
hm.put("Nancy", new ArrayList<>());
hm.get("Nancy").add(7);
hm.get("Nancy").add(8);
hm.get("Nancy").add(8);
hm.put("Lily", new ArrayList<>());
hm.get("Lily").add(9);
hm.get("Lily").add(9);
hm.get("Lily").add(8);
System.out.println("Find the average of the Peter");
float num = getAverage(hm, "Peter");
}
}
Related
I am trying to beat a sololearn challenge where we store the name of a player in a hashmap and then I am needed to iterate through the values of each player hashmap and get the name of the player with the highest score. I have been given a template code but do not have any idea on how to complete the class Bowling with a method called getWinner() to get the name of the player with the maximum points please help
import java.util.*;
public class Bowling {
HashMap<String, Integer> players;
Bowling() {
players = new HashMap<String, Integer>();
}
public void addPlayer(String name, int p) {
players.put(name, p);
}
//your code goes here
void getWinner(){
//help me complete this to get the name or the winner
}
}
public class Program {
public static void main(String[ ] args) {
Bowling game = new Bowling();
Scanner sc = new Scanner(System.in);
for(int i=0;i<3;i++) {
String input = sc.nextLine();
String[] values = input.split(" ");
String name = values[0];
int points = Integer.parseInt(values[1]);
game.addPlayer(name, points);
}
game.getWinner();
}
}
You get the entrySet (key, value), use a Comparator and compare them by the value and use Collections.max() to get the highest value. After this just get the key and you have the player name:
Collections.max(players.entrySet(), Comparator.comparingInt(Map.Entry::getValue)).getKey();
You can get all key from a map with keySet() and so get the values associated to the key. So here a key would be the name of a player and the values is score.
So here is a simple answer if there is no tie :).
void getWinner(){
int currentBestScore = 0;
String currentWinner = "nobody"
for ( String playerName : players.keySet() ) {
if(players.get(playerName)>=currentBestScore){
currentWinner = playerName;
}
}
System.out.println(playerName);
}
A question from a total newbie. Sorry.
I have this customersOrders HashMap that takes String as keys and ArrayList<Double> as values. I need to find the total sum of orders for each customer and the maximum total sum in order to find the biggest customer. How do I manage to do that using just nested For loops and HashMap methods? I'm totally stuck on that.
public class Test {
public static void main(String[] args) {
HashMap<String, ArrayList<Double>> customersOrders;
customersOrders = new HashMap<>();
ArrayList<Double> orders = new ArrayList<>();
orders.add(55.50);
orders.add(78.30);
orders.add(124.75);
customersOrders.put("John", orders);
orders = new ArrayList<>();
orders.add(28.35);
orders.add(37.40);
customersOrders.put("Helen", orders);
orders = new ArrayList<>();
orders.add(150.10);
customersOrders.put("Thomas", orders);
orders = new ArrayList<>();
orders.add(230.45);
orders.add(347.20);
customersOrders.put("Robert", orders);
orders = new ArrayList<>();
orders.add(530.25);
orders.add(325.40);
orders.add(11550.70);
orders.add(2480.65);
customersOrders.put("Jennifer", orders);
System.out.println(customersOrders);
}
}
So far I've been trying to do something like this but obviously with no success:
double maxOrder = 0;
String customerName = "";
for (ArrayList<Double> orders : customersOrders.values()) {
for (double orderPrice : orders) {
if (orderPrice > maxOrder) {
maxOrder = orderPrice;
}
}
}
for (String name : customersOrders.keySet()) {
if (maxOrder.equals(customersOrders.get(name))) {
customerName = name;
break;
}
}
You could create another HashMap which keeps your sums and then find the maximum of them.
First iterate through all your HashMap keys and find the sums for each customer like this:
HashMap<String, ArrayList<Double>> customerOrders = new HashMap<>();
// Fill your HashMap as you've done above
HashMap<String, Double> customerSums = new HashMap<>(); // The new HashMap that keeps the sums
for (String customerName : customerOrders.keySet()) // Foreach customer
{
double currentSum = 0;
for (Double aDouble : customerOrders.get(customerName))
{
currentSum += aDouble; // Sum the orders
}
customerSums.put(customerName, currentSum); // Put the sum in your new HashMap
}
Now finding the maximum should be very straightforward. Try to do that :D
Maybe something like this:
Map<String, Double> customersSum = new HashMap<>();
Double maxSum = Double.MIN_VALUE;
String customerWithMaxSum;
for (Map.Entry<String, List<Double>> entry: customersOrders.entrySet()) {
String customerId = entry.getKey();
List<Double> customerOrders = entry.getValue();
Double customerSum = customerOrders.stream().mapToDouble(d -> d).sum();
customersSum.put(customerId, customerSum);
if (customerSum > maxSum) {
maxSum = customerSum;
customerWithMaxSum = customerId;
}
}
Also could use stream pi for the second part:
Optional<String> customerWithMaxSum = customersSum.entrySet()
.stream()
.max(Comparator.comparingDouble(Map.Entry::getValue))
.map(Map.Entry::getKey);
Your logic code is not correct
for (double orderPrice : orders) {
if (orderPrice > maxOrder) {
maxOrder = orderPrice;
}
}
You are not adding the prices then comparing with maxOrder you instead compare each price with maxOrder. this is not what was required in your question.
You should do this instead
double ordersSum = 0;
for (double orderPrice : orders) {
ordersSum += orderPrice;
}
if (ordersSum > maxOrder) {
maxOrder = ordersSum;
}
and in your second for loop, you are comparing a double value with an arraylist which should result a compilation error you should compare the sum for products from each custom to maxOrder.
I should note here that this code is not very efficient you can instead loop on keys as you did in the second loop then calculate the sum inside of it and compare to maxOrder I will leave this implementation as an exercise for you.
You are iterating over the values in the orders Map. This doesn't tell you who that is associated with. Instead, you could iterate over the keyset or entryset, calculate the sum for that customer, and compare this to a running maximum. Since you specified using for-loops, the following excludes use of the Stream API.
String maxOrderCustomer = null;
double maxOrder = 0.0;
for (Map.EntrySet<String,List<Double>> entry : customerOrders.entrySet()) {
Double sum = 0.0;
for (Double order : entry.getValue();
sum += order;
}
if (order > maxOrder) {
maxOrder = order;
maxOrderCustomer = entry.getKey();
}
}
At this point, you will have the name of the customer with the largest sum and that sum value. If you want to display the relevant list of orders, you can use the name to pull the list from the original Map.
So I have this program that calculates the sum of all the petshops with the same key but different values. However, now, I would like to calculate the average of each petshop with the same key. I was thinking about using a counter in order to get how many times a petshop is contained in the arraylist. But it does not work. would I need to run another for each loop?
public class AverageCost {
public void calc(ArrayList<Pet> pets) {
Map<String, Double> hm = new HashMap<>();
for (Pet i : pets) {
String name = i.getShop();
// If the map already has the pet use the current value, otherwise 0.
double price = hm.containsKey(name) ? hm.get(name) : 0;
price += i.getPrice();
hm.put(name, price);
}
System.out.println("");
for (String key : hm.keySet()) {
System.out.printf("%s: %s%n", key, hm.get(key));
}
}
What you are asking for is an algorithm to calculate the cumulative moving average without storing the number of terms you have so far accumulated. I don't think this is possible (for example see https://en.wikipedia.org/wiki/Moving_average#Cumulative_moving_average where 'n', the number of terms so far, is required). My suggestion is to use two passes - the first to store the numbers and the second to calculate the averages.
public void calc(List<Pet> pets) {
// First pass
Map<String, List<Double>> firstPass = new HashMap<>();
for (Pet pet : pets) {
String name = pet.getShop();
if (firstPass.containsKey(name)) {
firstPass.get(name).add(pet.getPrice());
} else {
List<Double> prices = new ArrayList<>();
prices.add(pet.getPrice());
firstPass.put(name, prices);
}
}
// Second pass
Map<String, Double> results = new HashMap<>();
for (Map.Entry<String, List<Double>> entry : firstPass.entrySet()) {
Double average = calcAverage(entry.getValue());
results.put(entry.getKey(), average);
// Print results
System.out.printf("%s: %s%n", entry.getKey(), average);
}
}
private double calcAverage(List<Double> values) {
double result = 0;
for (Double value : values) {
result += value;
}
return result / values.size();
}
You can introduce second map for counting or use compound value object in your map to hold both accumulated price and number of pets:
Map<String, PetStatistics> hm = new HashMap<>();
for (Pet i : pets) {
String name = i.getShop();
// If the map already has the pet use the current value, otherwise 0.
PetStatistics stats = hm.get(name);
if (stats == null) {
stats = new PetStatistics(0, 0); // count and price
hm.put(name, stats);
}
stats.addPrice(i.getPrice());
stats.incrementCount();
}
You can use the Collections.frequency to get the number of occurrence and divide the whole sum
for (String key : hm.keySet()) {
int w = Collections.frequency(pets, new Pet(key));
System.out.printf("%s: %s%n", key, hm.get(key)/w);
}
This is from a project that I recently submitted, and I'm kind of frustrated that I couldn't figure this out.
I've got an ArrayList of my objects called studentList; the Student objects' state consists of the following:
private String studentName;
private double quiz1;
private double quiz2;
private double quiz3;
private double quiz4;
private double midTermOne;
private double midTermTwo;
private double finalTest;
private String letterGrade;
I couldn't figure out how to modularize the following code in order to prevent repeating it for each column (i.e. test scores for a student):
...
double quiz1Total = 0.0;
double quiz1Avg = 0.0;
double quiz1min = studentsList.get(0).getQuiz1();
double quiz1max = studentsList.get(0).getQuiz1();
for (int i = 0; i < studentsList.size(); i++) {
quiz1Total += studentsList.get(i).getQuiz1();
if (studentsList.get(i).getQuiz1() > quiz1max) {
quiz1max = studentsList.get(i).getQuiz1();
} // if
if (studentsList.get(i).getQuiz1() < quiz1min){
quiz1min = studentsList.get(i).getQuiz1();
} // if
} // for
quiz1Avg = quiz1Total / studentsList.size();
...
Is the recommendation to extract the test scores into a temp array first and then just pass that to the average/min/max method?
I'm not having trouble with the average/min/max concepts, just the model that I should be using so that I can modularize it.
Thanks.
In Java 8 you could use a method reference or lambda.
But I would simply change the way all of your data is stored in your student class. You could use an array, but I'd use an enum:
public enum Quiz {
QUIZ_1,
QUIZ_2,
QUIZ_3,
QUIZ_4,
MID_TERM_1,
MID_TERM_2,
FINAL_TEST
}
public final class Student {
private final EnumMap<Quiz, Double> grades
= new EnumMap<>(Quiz.class);
public void setGrade(Quiz quiz, double grade) {
grades.put(quiz, grade);
}
public double getGrade(Quiz quiz) {
Double grade = grades.get(quiz);
if (grade == null) {
throw new IllegalArgumentException(
"Student has no grade yet for quiz " + quiz);
}
return grade;
}
}
static double computeAverage(List<Student> students, Quiz quiz) {
double sum = 0;
for (Student student : students) {
sum += student.getGrade(quiz);
}
return sum / students.size();
}
Update: Since you mentioned that you are using Java 8, there's an even easier way, which makes use of some advanced Java 8 features.
Assuming your Student class has methods like getQuiz1(), getQuiz2(), etc., you could do:
List<Student> students = ...
DoubleSummaryStatistics stats = students.stream()
.mapToDouble(Student::getQuiz1)
.summaryStatistics();
double quiz1average = stats.getAverage();
double quiz1max = stats.getMax();
// etc.
// And likewise for quiz2:
DoubleSummaryStatistics stats = students.stream()
.mapToDouble(Student::getQuiz2)
.summaryStatistics();
That is what structures like Arrays are good for.
Either extract the four quizes into an array or, if are allowed to, modify the student class to represent them as an Array in the first place. So your code will look something like:
for every quiz
for every student
...
Is the recommendation to extract the test scores into a temp array first and then just pass that to the average/min/max method?
Yes, you could do that. Or you could store them in arrays to begin with:
class Student {
double[] scores = new double[7];
static final int QUIZ1 = 0;
static final int QUIZ2 = 1;
...
static double average(Student[] students, int scoreIndex) {
...
for(Student student : students) {
sum += student.scores[scoreIndex];
}
...
}
}
(That might be unwieldy in practice, but probably uses concepts you are familiar with.)
Or you could use a Map:
class Student {
Map<String, Double> scores = new HashMap<>();
Student() {
scores.put("quiz1", 0);
scores.put("quiz2", 0);
...
}
static double average(Student[] students, String scoreKey) {
...
for(Student student : students) {
sum += student.scores.get(scoreKey);
}
...
}
}
Assuming quizzes are identifiable, let's say by a String name (or id, whatever), you should store their results for each student in a map:
private Map<String, Double> results = new HashMap<>();
Then add methods to student to get/set the results for a quiz:
public double getResult(String quiz) {
if (results.containsKey(quiz))
return results.get(quiz);
return 0; // hasn't done quiz, so zero score
}
public void setResult(String quiz, double result) {
results.put(quiz, result);
}
Then to calculate an average for a quiz for a some students:
public static double average(Collection<Student> students, String quiz) {
double total = 0;
for (Student student : students)
total += student.getResult(quiz);
return total / students.size();
}
You probably want to represent quiz1 quiz2 ect... as an array so something like this in your student object
class Student {
double[] myQuizs = new double[4];
public double[] getQuizScores(){
return myQuizs;
}
public double getQuiz(double num){
return myQuizs[n];
}
}
then you could do this:
double quizTotal[] = {0,0,0,0};
double quizNAvg[] = {0,0,0,0};
double quizNMin[] = new double[4];
double quizNMax[] = new double[4];
for (int n = 0; n < 4; n++){
for (int i = 0; i < studentsList.size(); i++) {
quizTotal[n] += studentsList.get(i).getQuiz1();
if (studentsList.get(i).getQuiz(n) > quizNMax[n])
quizNMax[n] = studentsList.get(i).getQuiz(n);
if (studentsList.get(i).getQuiz(n) < quizNMin[n])
quizNMin[n] = studentsList.get(i).getQuiz(n);
}
}
4 is the number of quizes i am assuming that there are. You could change that number.
You should modifie quizTotal and quizNAvg so that they have the ammount of quizes as they do elements.
In the Student class, I need to add a method to put a new course into the student's course collection and a method that calculates and returns the student's average grade. I keep getting "NaN" as a result when I try to calculate the student's average grade. Would appreciate any help. Thanks.
Below is my source code for the Student class.
import java.util.HashMap;
import java.util.Set;
public class Student extends Member
{
// instance variables of class Student
private HashMap<String, Double> courses;
public Student()
{
super();
courses = new HashMap<String, Double>();
}
/**
* Constructor
* #param firstName
* #param lastName
* #param emailAddress
* #param bcitId
*/
public Student(String firstName, String lastName, String emailAddress, String bcitId)
{
super(firstName, lastName, emailAddress, bcitId);
courses = new HashMap<String, Double>();
}
public void addCourse(String course, Double grade)
{
if(!courses.isEmpty()) {
courses.put(course, grade);
}
}
public Double getAverageGrade()
{
Double averageGrade = 0.0;
int counter = 0;
if(!courses.isEmpty()){
Set<String> course = courses.keySet();
for(String grade : course){
averageGrade += courses.get(grade);
counter++;
}
}
return (averageGrade /= counter);
}
}
Your method
public void addCourse(String course, Double grade)
{
if(!courses.isEmpty()) {
courses.put(course, grade);
}
}
looks funny to me. Do you intend to only add a course if there is already at least one course in the map? This way, how will the first course enter the map?
I think you tried to check for the map to exist, but that would be done differently, namely:
if (courses == null){
...
}
About the division problem look at the other answer from Saposhiente. I would only repeat it...
int counter = 0;
return (averageGrade /= counter);
NaN indicates division by zero, among other things. Counter was never incremented because no courses were added; see luksch's answer for why. Also, since you will never reference averageGrade again, you can simply use
return averageGrade / counter;
which is slightly more efficient.
The only way it's going to return NaN is when the courses.isEmpty() returns true as the couter will not be incremented and you will divide by 0.
Also you could improve your cycle by using getValues()
public Double getAverageGrade()
{
Double averageGrade = 0.0;
int counter = 0;
if(!courses.isEmpty()){
for(Double grade : courses.getValues()){
averageGrade += grade
counter++;
}
} else {
return -1; // or some value that says that are no grades yet
}
return (averageGrade /= counter);
}
Here you go with a simple HashMap technique , refer the Below code for Caluclating
average and find the Beststudent from it,Understand it well , I might help you
Thanks...
import java.util.*;
public class QueQue {
public static float getAverage(HashMap<String, ArrayList<Integer>> hm, String name) {
ArrayList<Integer> scores;
scores = hm.get(name);
if (scores == null) {
System.out.println("NOT found");
}
int sum = 0;
for (int x : scores) {
sum += x;
}
return (float) sum / scores.size();
}
// The best students from these Key-Value Pair
public static String getBestStudent(HashMap<String, ArrayList<Integer>> hm) {
double max = 0;
String beststudent = null;
for (Map.Entry<String, ArrayList<Integer>> x : hm.entrySet()) {
String name = x.getKey();
double average = getAverage(hm, name);
if (average > max) {
max = average;
beststudent = name;
}
}
return beststudent;
}
public static void main(String[] args) {
HashMap<String, ArrayList<Integer>> hm = new HashMap<>();
hm.put("Peter", new ArrayList<>());
hm.get("Peter").add(10);
hm.get("Peter").add(10);
hm.get("Peter").add(10);
hm.put("Nancy", new ArrayList<>());
hm.get("Nancy").add(7);
hm.get("Nancy").add(8);
hm.get("Nancy").add(8);
hm.put("Lily", new ArrayList<>());
hm.get("Lily").add(9);
hm.get("Lily").add(9);
hm.get("Lily").add(8);
System.out.println("Find the average of the Peter");
float num = getAverage(hm, "Peter");
System.out.println(num);
String name = getBestStudent(hm);
System.out.println(name);
}
}