I have 5 lists of years and 5 lists of amounts corresponding to year lists.
year_Earnings = [2011,2012,2013];
year_Expense = [2011,2012];
year_Investment = [2013];
year_Returns=[];
year_Savings=[2011,2012,2013];
amount_Earnings = [10,20,7];
amount_Expense = [5,10];
amount_Investment = [5];
amount_Returns=[];
amount_Savings=[5,10,7];
obviously i will get ArrayIndexOutOfBoundException when i try to iterate all the lists in a single for loop. so i converted this all lists in to hash maps with key value pairs by using below code
Map<Double, Double> earningsMap = listToMap(year_Earnings, amount_Earnings);
Map<Double, Double> expensesMap = listToMap(year_Expense, amount_Expense);
Map<Double, Double> investmentMap = listToMap(year_Investment, amount_Investment);
Map<Double, Double> returnsMap = listToMap(year_Returns, amount_Returns);
Map<Double, Double> savingsMap = listToMap(year_Savings, amount_Savings);
public Map<Double, Double> listToMap(List<Double> years, List<Double> money) {
Map<Double, Double> newMap = new HashMap<Double, Double>();
if (years == null || money == null || years.size() != money.size()) {
throw new IllegalArgumentException();
}
for (int i=0; i< years.size(); i++ ) {
newMap.put(years.get(i), money.get(i));
}
return newMap;
}
now i want list like below
year_Earnings = [2011,2012,2013];
year_Expense = [2011,2012,2013];
year_Investment = [2011,2012,2013];
year_Returns=[2011,2012,2013];
year_Savings=[2011,2012,2013];
amount_Earnings = [10,20,7];
amount_Expense = [5,10,0];
amount_Investment = [0,0,5];
amount_Returns=[0,0,0];
amount_Savings=[5,10,7];
can anyone please help me in doing this stuff.. thank u in advance
I have 5 lists of years and 5 lists of amounts corresponding to year
lists.
=> This is bad solution because if you follow this then you have to manage 10 lists, Instead I would suggest you to create Only Single ArrayList<Object>, every item will be of Object type.
1) Define one class Earnings with getter/setter methods.
public class Earning {
int year;
int amount;
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
this.amount = amount;
}
}
2) Define ArrayList<Earning> type, create object of Earnings type whenever you want and put it inside the ArrayList.
Instead of having such complicate and robust architecture i suggest you to work on it.
Enum that store the types of transaction
public enum FinancialType {
EARNING,
EXPENSE,
INVESTMENT,
RETURN,
SAVING;
}
Class that will store the
public class FinancialOperation {
private final FinancialType type;
private final int year;
private final BigDecimal value;
}
The util method that will transform then lists into structure.
private List<FinancialOperation> createFinancialOperation(FinancialType type, List<Double> years, List<Double> money) {
List<FinancialOperation> result = new ArrayList<>();
for(int i = 0; i < years.size(); i++) {
Double year = years.get(i);
Double money = moneys.get(i);
if(year == null) {
continue; //or throw
}
BigDecimal amount = BigDecimal.ZERO;
if(money != null) {
amount = new BigDecimal(money,MathContext.DECIMAL128);
}
result.add(new FinancialOperation(type,year.intValue(),amount);
}
return result;
}
The usage is quite simple to imagine.
List<FinancialOperation> earningsList = createFinancialOperation(FinancialType.EARNING,year_Earnings, amount_Earnings);
List<FinancialOperation> investmentList = createFinancialOperation(FinancialType.INVESTMENT,year_Investment, amount_Investment);
and
Map<FinancialType,List<FinancialOperation>> map = new HashMap<>();
map.put(FinancialType.EARNING,earningsList);
map.put(FinancialType.INVESTMENT,investmentList);
ArrayIndexOutOfBoundException excepts because your lists are of different size... Use the same size in all lists, and this error will dissapear...
You can do it without any additional data structure, using the following utility method:
public static int[] values(int[] arr, int[] years, int firstYear, int lastYear) {
int[] res = new int[lastYear-firstYear+1];
int arrPos = 0;
for(int i = 0; i < res.length; i++) {
int year = firstYear + i;
if (arrPos==arr.length || years[arrPos] > year)
res[i] = 0;
else
res[i] = arr[arrPos++];
}
return res;
}
The input array arr can have any number of gaps, and the output will be an array corresponding to consecutive years, from firstYear to lastYear.
It requires that you first find the minimum and maximum year value in all year arrays.
Related
Could someone help me figure out why this version of the memoized coin change doesn't work?
This is to determine the minimum number of coins to make change for a target amount.
I realize that the cache is putting in the wrong values and without using the memo cache this gives the right answer. I was also able to get a memoized version to work by not passing in the currNumCoins as an argument to the recursive calls. I'm just stumped to why this version doesn't work.
I'm initializing memo as Map<Integer, Integer> memo = new HashMap<>();
Example input: coins = [1,2,5], targetAmount = 11
Expected Answer : 3
Actual Answer: 7
class Solution {
Map<Integer, Integer> memo = new HashMap<>();
public int coinChange(int[] coins, int amount) {
return coinChangeRecHelper(coins, amount, amount, 0);
}
public int coinChangeRecHelper(int[] coins, int amount, int currAmount, int currNumCoins) {
if (currAmount < 0) {
return -1;
}
if (currAmount == 0) {
//return 0;
return currNumCoins;
}
if (memo.containsKey(currAmount)) {
return memo.get(currAmount);
}
int minCoins = Integer.MAX_VALUE;
for (int i = 0; i < coins.length; i++) {
int currCoin = coins[i];
int numCoinsTmp = coinChangeRecHelper(coins, amount, currAmount - currCoin, currNumCoins + 1);
if (numCoinsTmp != -1) {
minCoins = Math.min(minCoins, numCoinsTmp);
}
}
if (minCoins == Integer.MAX_VALUE) {
minCoins = -1;
}
memo.put(currAmount, minCoins);
return minCoins;
}
}
You need a separate memo for each recursion so one does not change the other.
For example memorizing which coins where used can be achieved like so:
import java.util.HashMap;
import java.util.Map;
public class Solution {
private Map<Integer, Integer> memo;
public int coinChange(int[] coins, int amount) {
memo = new HashMap<>();
return coinChangeRecHelper(coins, amount, amount, 0, new HashMap<Integer,Integer>());
}
public int coinChangeRecHelper(int[] coins, int amount, int currAmount, int currNumCoins, Map<Integer, Integer> coinQty ) {
if (currAmount < 0) return -1;
if (currAmount == 0) {
memo = coinQty;
return currNumCoins;
}
int minCoins = Integer.MAX_VALUE;
for (int currCoin : coins) {
Map<Integer, Integer> coinQtyCopy = new HashMap<>(coinQty);
coinQtyCopy.putIfAbsent(currCoin, 0);
coinQtyCopy.put(currCoin, coinQtyCopy.get(currCoin)+1);
int numCoinsTmp = coinChangeRecHelper(coins, amount, currAmount - currCoin, currNumCoins + 1, coinQtyCopy);
if (numCoinsTmp != -1) {
minCoins = Math.min(minCoins, numCoinsTmp);
}
}
if (minCoins == Integer.MAX_VALUE) {
minCoins = -1;
}
return minCoins;
}
public Map<Integer, Integer> getMemo() {
return memo;
}
public static void main(String[] args) {
Solution s = new Solution();
System.out.println(s.coinChange(new int[]{1,2,5}, 11) + " coins used: ");
for(int coin : s.getMemo().keySet()) {
System.out.println( s.getMemo().get(coin)+ " of " + coin);
}
}
}
The return-value of coinChangeRecHelper depends on three of its arguments (coins, currAmount, and currNumCoins), but the memo cache is keyed by only one of those values (currAmount), which inherently means that it can't accurately cache the return-value. In other words, the code implicitly assumes that coinChangeRecHelper(coins1, amount1, currAmount, currNumCoins1) == coinChangeRecHelper(coins2, amount2, currAmount, currNumCoins2), but that's a bad assumption.
I was also able to get a memoized version to work by not passing in the currNumCoins as an argument to the recursive calls.
Yes, that approach would mostly fix this issue, by eliminating a mismatched parameter that the caching doesn't account for.
The only remaining issue is coins; if your coinChange method is called twice with different sets of coins, it will erroneously retain the old cache even though it's not applicable to the new call. To fix that, I'd recommend having coinChange create the cache and pass it as an argument to coinChangeRecHelper, rather than using an instance variable.
I'm doing something that produces the right result. However, it is wrong from a design POV.
The point of the program is to list the result of all the powers of a number up to and including the user-defined limit.
I have a constructor which accepts the base and the exponent from the Scanner. Then a method, which utilises a for loop to calculate the power for each exponent.
Now, the problem is that I'm printing the result from each loop iteration directly from this method. This beats the point of private variables and it being void in the 1st place.
Therefore, I want to define a getter method which returns the result of each power to the output. I used to set them just fine for if/switch statements, but I don't know how to do the same for loops. If I assign the result to a variable within the loop and return that variable from the getter then it will return only the output from the final iteration.
Private implementation
package Chapter6Review;
public class Powers {
private int target;
private int power;
public Powers(int target, int power) {
this.target = target;
this.power = power;
}
public void calculatePower() {
for (int i = 0; i <= power; i++) {
System.out.println((int) Math.pow(target, i));
}
}
/*
public int getPower() {
return
}
*/
}
User interface
package Chapter6Review;
import java.util.Scanner;
public class PowersTester {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.print("Enter your base: ");
int target = in.nextInt();
System.out.print("Enter your exponent: ");
int power = in.nextInt();
Powers tester = new Powers(target, power);
tester.calculatePower();
}
}
You can simply use a List ;
public List<Integer> calculatePower() {
int p;
List<Integer> result = new ArrayList<Integer>();
for (int i = 0; i <= power; i++) {
p = (int) Math.pow(target, i);
result.add(p);
}
return result;
}
Then in you main method, you can iterate the list to print the powers like that :
List<Integer> result = new ArrayList<Integer>();
Powers tester = new Powers(target, power);
result = tester.calculatePower();
for (int i = 0; i < result.size(); i++) {
System.out.println(result.get(i));
}
You could store each of the results in a List:
List<Power> list = new ArrayList<>();
and when you call it add it as well
list.add(new Powers(target, power));
At the end you can iterate over the list like this:
for (Power power : list){
// your code
}
You might consider using streams as well
public List<Integer> calculatePower() {
return IntStream
.rangeClosed(0, power). // iterate from 0 till power inclusive
.mapToObj(i -> (int) Math.pow(target,i))
.collect(Collectors.toList()); // get result as list
}
Thanks for all the answers. Using a list seems to be a good choice.
Since I haven't covered lists yet, I resorted to this solution for now. But I don't like having code that can affect the solution in the main. Ideally, the loop should go in the private implementation.
Main
Powers tester = new Powers(target, power);
for (int i = 0; i <= power; i++) {
tester.calculatePower(i);
System.out.println(tester.getPower());
}
Private implementation
public void calculatePower(int iPower) {
result = (int) Math.pow(target, iPower);
}
public int getPower() {
return result;
}
I have two ArrayLists.
List of dates
List of respective data.
Both are synchronized. I sometimes have more than one data on a same date. I need to create two lists: unique dates and the data (averaged) respectively. So far, I have tried the following methods
int i = 1;
for(int it =0; it < predatetime.size() - 1; it++){
//Compare each element with the next one
if(predatetime.get(it+1) == predatetime.get(it)){
i++;
weight = preweight.get(it+1) + weight;
//If equal, add weights and increment a divisor for averaging
}
else { //if not equal, add to the new lists
if(it == predatetime.size() - 2){ //if the last element is not equal to its previous one, just add it to the list
newDateTime.add(predatetime.get(it+1));
newWeight.add(preweight.get(it+1));
break;
}
weight = weight / i;
newDateTime.add(predatetime.get(it));
newWeight.add(weight);
weight = preweight.get(it+1); //re-initialize variables
i = 1;
}
if(it == predatetime.size() - 2){
weight = weight / i;
newDateTime.add(predatetime.get(it));
newWeight.add(weight);
}
}
There are a lot of problems with this code.
If the list has only one element, it fails. (I know I can write 2 more lines to care of this). Is there a better way to do this?
I know there are similar questions on this website, but still I'm unable to resolve the problem.
This is the full solution
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
public class CustomList {
public static void main(String[] args) {
ArrayList<String> date = new ArrayList<>();
date.add("1");
date.add("2");
date.add("2");
date.add("3");
System.out.println(date);
ArrayList<Integer> value = new ArrayList<>();
value.add(1);
value.add(2);
value.add(4);
value.add(3);
System.out.println(value);
new MyCls().createList(date, value);
}
}
class MyCls {
ArrayList uniqueDate = new ArrayList<String>();
ArrayList averageValue = new ArrayList<Integer>();
LinkedHashMap store = new LinkedHashMap<String, CountEntry>();
class CountEntry {
int value;
int count;
CountEntry() {
}
CountEntry(int v, int c) {
value = v;
count = c;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
public void createList(ArrayList<String> date, ArrayList<Integer> value) {
for (int i = 0; i < date.size(); i++) {
CountEntry tmp = (CountEntry) store.get(date.get(i));
if (tmp == null) {
store.put(date.get(i), new CountEntry(value.get(i), 1));
} else {
int tmpVal = tmp.getValue();
int tmpCount = tmp.getCount();
store.put(date.get(i), new CountEntry(value.get(i) + tmpVal, ++tmpCount));
}
}
ArrayList<String> uniqueDate = new ArrayList<String>(store.keySet());
ArrayList<CountEntry> tempAvgList = new ArrayList<CountEntry>(store.values());
for (CountEntry ce : tempAvgList) {
averageValue.add(ce.getValue() / ce.getCount());
}
System.out.println("Output");
System.out.println(uniqueDate);
System.out.println(averageValue);
}
}
/*
OUTPUT Snap:
[1, 2, 2, 3]
[1, 2, 4, 3]
Output
[1, 2, 3]
[1, 3, 3]
*/
If you try to make your list elements unique why you not try to convert the list to set collection
Set<Foo> foo = new HashSet<Foo>(myList);
Why not create a Map instead with the dates as the key and have the value as a list. This will allow you to keep the dates unique, at the same allow you to have your data as a list.
Map<String, ArrayList<myData>> myMap = new HashMap<String, ArrayList<myData>>();
Then you can just find if your key exists, if it does add it to the array list by using the key to identify the correct list. If it doesnt exist it, add it to the map
Thanks to #Rambler and #JulianGurung, I created a HashMap and it works
HashMap<Integer, Float> hm = new HashMap<Integer,Float>();
int occurance = 0;
float weight = 0;
hm.put(predatetime.get(0), 0f); //initialize with the first value
for(Map.Entry m : hm.entrySet()){
for( int it = 0; it < predatetime.size(); it++){
if(m.getKey() == predatetime.get(it)){
weight = (Float) m.getValue() + preweight.get(it); //Sum all the same data in order to avg later
hm.put(predatetime.get(it), weight);
occurance++;
}
else{ //if it is not equal, add the new element to the map
hm.put(predatetime.get(it), preweight.get(it));
}
}
weight = weight / occurance;
hm.put((Integer) m.getKey(), weight);
weight = 0;
occurance = 0;
}
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);
}
}