Your program must read the id number and gpa and transfer the data into two separate arrays. You can assume there will never be more than 1000 students in the file. Do you know why you must use two separate arrays? You may find it useful in this program to create additional arrays to complete the requirements of the program as described next.
Your program must do two distinctly different things correctly for full credit:
You must create a simple diagram to show how many students fall into each of 8 different categories. This type of diagram is known as a histogram and it is generally useful to show how data is distributed across a range.
For each student in the input file, you must display their S-number, gpa, and class rank. The S-number and gpa will already be in your arrays; however, you must calculate their class rank.
Here is the code I have so far:
public static void main(String[] args) throws Exception
{
Scanner gpadata;
String snum;
double gpa;
int groupNumber;
gpadata = new Scanner(new File("studentdata.txt"));
while (gpadata.hasNext())
{
snum = gpadata.next();
gpa = gpadata.nextDouble();
groupNumber = gpaGroup(gpa);
System.out.println("Student number, GPA, and group number"
+ " is: " + snum +
" " + gpa + " " + groupNumber);
}
}
//Method to categorize students GPA into 1 of 8 groups
public static int gpaGroup(double gpa)
{
//Declare all variables
int gpaGroup;
//Assign GPA a group number
if (gpa >= 0.0 && gpa < 0.5)
gpaGroup = 1;
else if (gpa >= 0.5 && gpa < 1.0)
gpaGroup = 2;
else if (gpa >= 1.0 && gpa < 1.5)
gpaGroup = 3;
else if (gpa >= 1.5 && gpa < 2.0)
gpaGroup = 3;
else if (gpa >= 2.0 && gpa < 2.5)
gpaGroup = 4;
else if (gpa >= 2.5 && gpa < 3.0)
gpaGroup = 5;
else if (gpa >= 3.0 && gpa < 3.5)
gpaGroup = 6;
else
gpaGroup = 7;
//Return int value of group number
return gpaGroup;
}
//Method to find number of students in each group
public static void studentsInGroup(int gpaGroup)
{
//Declare all variables
int gpaGroup1 = 0;
int gpaGroup2 = 0;
int gpaGroup3 = 0;
int gpaGroup4 = 0;
int gpaGroup5 = 0;
int gpaGroup6 = 0;
int gpaGroup7 = 0;
int gpaGroup8 = 0;
//Total students in each GPA group
if (gpaGroup == 1)
gpaGroup1++;
else if (gpaGroup == 2)
gpaGroup2++;
else if (gpaGroup == 3)
gpaGroup3++;
else if (gpaGroup == 4)
gpaGroup4++;
else if (gpaGroup == 5)
gpaGroup5++;
else if (gpaGroup == 6)
gpaGroup6++;
else if (gpaGroup == 7)
gpaGroup7++;
else
gpaGroup8++;
}
Can I modify my method to return more than one variable from a method (in public static void studentsInGroup(int gpaGroup) return values of number of students in each group)? Is this where arrays start to come in? From here I would write another method to round number of students in each category to the nearest ten, then use this to write a method for creating a histogram etc etc.
I have been trying my hardest to understand the concepts, but I have been struggling lately. This is one of my last assignments for the semester and I'd like to keep my A, and also understand what I'm doing.
Can I modify my method to return more than one variable from a method (in public static void studentsInGroup(int gpaGroup) return values of number of students in each group)?
Yes, you can. You can create an object that contains two variables. However, the instructions suggest a different solution.
Inside your loop, read the id and gpa, and immediately stick them in two separate arrays.
Here is a fragment:
snums = [];
gpas = [];
while (gpadata.hasNext())
{
snum = gpadata.next();
gpa = gpadata.nextDouble();
snums.append(snum);
gpas.append(gpa);
}
ensure you are doing the following. I'm not giving away any code here. Also not sure why they want you to use array only!?!
Breakdown your requirement and see what you need to achieve.
Start with reading each line from file
each line is separated by " " and has id_number and gpa
from the requirement, the file will not contain more than 1000 students(1000 lines). You may declare this as a static class level variable static String[] idnum_array = new String[1000]; and another array for gpa which is Double[]
read each line and then separate by using String.split(" ") method. The first variable is your id number and 2nd will be your gpa. you follow ?
maintain a separate counter to increment the array position each time you set these values in the two arrays you created in step 3.
Integer i = 0;
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
String[] splitString = line.split(" ");
idnum_array[i] = String.valueOf(splitString[0]);
gpa_array[i] = Double.valueOf(splitString[1]);
i++;
}
Do you agree that if we do idnum_array[7] to return it's corresponding gpa result from gpa_array[7] for that student ?
How you choose to count the number of people in a certain group is upto you.
I would do the following
create a static class level variable static Integer[] group_array = new Integer[]{0,0,0,0,0,0,0,0}; // there are only 8 groups!
loop my gpa_array
have an if/else inside the loop to check which group it falls in
increment the value at that index by 1. group_array[index]++;
In the end I will have an array of 8 elements which will correspond to the 8 groups. [0,200,300,200,0,300,0,0,0]
You should end up with nearly 4 methods similar to this.
1. readDataFromFile(String fileName)
2. groupGPAIntoCategory()
3. drawHistogram()
4. calculateRank()
I would personally create a Student object from the very beginning.
It's just cleaner and readable. Make sure you have your try catch block to print your exceptions and always comment!
I still a little bit new so I'm going to include all of my java code and then explain what I am looking for.
import java.util.Scanner;
public class Part_I{
public static Scanner input = new Scanner(System.in);
public static String strInfo;
public static int number;
public static void main(String[] args){
String presidents[][] = {
{"1 ","George"," ","Washington"," (1789-1797) ","John Adams"},
{"2 ","John"," ","Adams"," (1797-1801) ","Thomas Jefferson"},
{"3 ","Thomas"," ","Jefferson"," (1801-1809) ","Aaron Burr"},
{"4 ","James"," ","Madison"," (1809-1817) ","George Clinton"},
{"5 ","James"," ","Monroe"," (1817-1825) ","Daniel D. Tompkins"},
{"6 ","John"," Quincy ","Adams"," (1825-1829) ","John C. Calhoun"},
{"7 ","Andrew"," ","Jackson"," (1829-1837) ","John C. Calhoun"},
{"8 ","Martin"," Van ","Buren"," (1837-1841) ","Richard M. Johnson"},
{"9 ","William"," Henry ","Harrison"," (1841) ","John Tyler"},
{"10 ","John"," ","Tyler"," (1841-1845) ","None"},
{"11 ","James"," K. ","Polk"," (1845-1849) ","George M. Dallas"},
{"12 ","Zachary"," ","Taylor"," (1849-1850) ","Millard Fillmore"},
{"13 ","Millard"," ","Fillmore"," (1850-1853) ","None"},
{"14 ","Franklin"," ","Pierce"," (1853-1857) ","William King"},
{"15 ","James"," ","Buchanan"," (1857-1861) ","John C. Breckinridge"},
{"16 ","Abraham"," ","Lincoln"," (1861-1865) ","Hannibal Hamlin"},
{"17 ","Andrew"," ","Johnson"," (1865-1869) ","None"},
{"18 ","Ulysses"," S. ","Grant"," (1869-1877) ","Schuyler Colfax"},
{"19 ","Rutherford"," B. ","Hayes"," (1877-1881) ","William Wheeler"},
{"20 ","James"," A. ","Garfield"," (1881) ","Chester Arthur"},
{"21 ","Chester"," ","Arthur"," (1881-1885) ","None"},
{"22 ","Grover"," ","Cleveland"," (1885-1889) ","Thomas Hendricks"},
{"23 ","Benjamin"," ","Harrison"," (1889-1893) ","Levi P. Morton"},
{"24 ","Grover"," ","Cleveland"," (1893-1897) ","Adlai E. Stevenson"},
{"25 ","William"," ","McKinley"," (1897-1901) ","Garret Hobart"},
{"26 ","Theodore"," ","Roosevelt"," (1901-1909) ","None"},
{"27 ","William"," Howard ","Taft"," (1909-1913) ","James S. Sherman"},
{"28 ","Woodrow"," ","Wilson"," (1913-1921) ","Thomas R. Marshall"},
{"29 ","Warren"," G. ","Harding"," (1921-1923) ","Calvin Coolidge"},
{"30 ","Calvin"," ","Coolidge"," (1923-1929) ","None"},
{"31 ","Herbert"," ","Hoover"," (1929-1933) ","Charles Curtis"},
{"32 ","Franklin"," D. ","Roosevelt"," (1933-1945) ","John Nance Garner"},
{"33 ","Harry"," S. ","Truman"," (1945-1953) ","None"},
{"34 ","Dwight"," D. ","Eisenhower"," (1953-1961) ","Richard Nixon"},
{"35 ","John"," F. ","Kennedy"," (1961-1963) ","Lyndon B. Johnson"},
{"36 ","Lyndon"," B. ","Johnson"," (1963-1969) ","None"},
{"37 ","Richard"," ","Nixon"," (1969-1974) ","Spiro Agnew"},
{"38 ","Gerald"," ","Ford"," (1974-1977) ","Nelson Rockefeller"},
{"39 ","Jimmy"," ","Carter"," (1977-1981) ","Walter Mondale"},
{"40 ","Ronald"," ","Reagan"," (1981-1989) ","George Bush"},
{"41 ","George"," ","Bush"," (1989-1993) ","Dan Quayle"},
{"42 ","Bill"," ","Clinton"," (1993-2001) ","Al Gore"},
{"43 ","George"," W. ","Bush"," (2001-2009) ","Dick Cheney"},
{"44 ","Barack"," ","Obama"," (2009-2017) ","Joe Biden"},
};
System.out.println("This will display the President and VP of the United States based on the number you provide.");
System.out.println("Please enter a number between 1 and 44 to see information or q to quit: ");
strInfo = input.nextLine();
while(strInfo != "q"){
if(isInteger(strInfo)){
number = Integer.parseInt(strInfo);
if (number >= 1 && number <=44){
System.out.println();
System.out.println(presidents[number-1][0] + "President " + presidents[number-1][1] + presidents[number-1][2] + presidents[number-1][3] + presidents[number-1][4] + "Vice President " + presidents[number-1][5]);
System.out.println();
System.out.println("Please enter a number between 1 and 44 to see information or q to quit: ");
strInfo = input.nextLine();
}else{
System.out.println();
System.out.println("Wrong Input! Please enter number 1-44 or q to quit.");
strInfo = input.nextLine();
}
}else{
System.out.println();
System.out.println("This program has been terminated. Good Bye!");
System.exit(0);
}
}
}
public static boolean isInteger(String strInfo){
if (strInfo == null) {
return false;
}
int length = strInfo.length();
if (length == 0) {
return false;
}
int i = 0;
if (strInfo.charAt(0) == '-') {
if (length == 1) {
return false;
}
i = 1;
}
for (; i < length; i++) {
char c = strInfo.charAt(i);
if (c < '0' || c > '9') {
return false;
}
}
return true;
}
}
My main concern is with the while loop.
while(strInfo != "q"){
if(isInteger(strInfo)){
number = Integer.parseInt(strInfo);
if (number >= 1 && number <=44){
System.out.println();
System.out.println(presidents[number-1][0] + "President " + presidents[number-1][1] + presidents[number-1][2] + presidents[number-1][3] + presidents[number-1][4] + "Vice President " + presidents[number-1][5]);
System.out.println();
System.out.println("Please enter a number between 1 and 44 to see information or q to quit: ");
strInfo = input.nextLine();
}else{
System.out.println();
System.out.println("Wrong Input! Please enter number 1-44 or q to quit.");
strInfo = input.nextLine();
}
}else{
System.out.println();
System.out.println("This program has been terminated. Good Bye!");
System.exit(0);
}
}
}
I want to make it so that it any string other than what is able to be converted to an int or "q" would say wrong input and make you input another string value. Right now, any string will make the program terminate. What should I change in that while loop and how should I change it or what should it look like instead so that if the string input is not q or convertible to an int will make wrong input display and ask for input again?
This will help you in achieving what you want to do
while (!strInfo.equals("q")) {
if (isInteger(strInfo)) {
number = Integer.parseInt(strInfo);
if (number >= 1 && number <= 44) {
System.out.println();
System.out.println(presidents[number - 1][0] + "President " + presidents[number - 1][1] + presidents[number - 1][2] + presidents[number - 1][3] + presidents[number - 1][4] + "Vice President " + presidents[number - 1][5]);
System.out.println();
System.out.println("Please enter a number between 1 and 44 to see information or q to quit: ");
strInfo = input.nextLine();
} else {
System.out.println();
System.out.println("Wrong Input! Please enter number 1-44 or q to quit.");
strInfo = input.nextLine();
}
} else {
System.out.println();
System.out.println("Wrong Input! Please enter number 1-44 or q to quit.");
strInfo = input.nextLine();
}
}
System.out.println();
System.out.println("This program has been terminated. Good Bye!");
System.exit(0);
You shouldn't check string equality using normal operators like "=" and "!=". Use the String .equals() method.
So your first line would be
while(!strInfo.equals("q"))
More info:
http://www.leepoint.net/data/expressions/22compareobjects.html
The reason your code is not working is because you are trying to compare whether the contents of two strings are equal using == operator (which only compares if the two references point to the same object). == Operator does not compare the contents of the two strings.
In order to make your code work, you would need to use equals to compare the contents of the two strings as follows :
while(!strInfo.equals("q"))
Now lets try to delve deep into why your code is not working. For that we need to understand the basic difference between == & equals
== Operator is used to compare if both the references on its either side point to the same object (Basically you can say its similar to
comparing address of the object to which the references point to).
Whereas equals in case of String compares the content of the two Strings. It is the responsibility of the creator of the class to override the default equals method to compare the objects of that class depending on what makes sense for that object. For example in case of String class the creators of the class have overriden the equals method to compare the contents of the Strings.
String a = "test"; // lets say the object guy has address : 24
String b = a; // now b points to the same object that is being referenced by a
System.out.println(a == b); // this will be true as both point to the same reference
System.out.println(a.equals(b)); // this will be true as the contents of both these strings is the same.
// Now lets consider a new strings having same content "test"
String c = "test";
System.out.println(a == c); // this will be false as both point to the different references or memory location
System.out.println(a.equals(c)); // this will be true as the contents of both these strings is the same.
I'm learning Java through a series of explanations and exercises, and one of them was to create a program that would display a number grade (0-5) in accordance to a number of points (0–29, 30–34, 35–39, 40–44, 45–49, 50–60).
System.out.println("Type the points [0-60]: ");
double points = reader.nextDouble();
reader.nextLine();
if (points < 29) {
System.out.println("Grade: FAILED.");
} else if (points <= 34) {
System.out.println("Grade: 1.");
} else if (points <= 39) {
System.out.println("Grade: 2.");
} else if (points <= 44) {
System.out.println("Grade: 3.");
} else if (points <= 49) {
System.out.println("Grade: 4.");
} else if (points >= 50) {
System.out.println("Grade: 5.");
}
The program works in that it'll give the correct grade because of the overlap in commands, but is there any way to create a range of numbers or strings that could meet the condition of the if/else statement? For example, if the number entered is between 40-44 and so on. Detailed answer would be appreciated since I'm new.
Divide the number by five, and make an array of twelve strings with the textual representation of the grade:
private static final String GRADE_FAILED = "FAILED";
private static final String GRADE_1 = "1";
private static final String GRADE_2 = "2";
private static final String GRADE_3 = "3";
private static final String GRADE_4 = "4";
private static final String GRADE_5 = "5";
private static String GradeStr[] = new {
GRADE_FAILED // 0..4
, GRADE_FAILED // 5..9
, GRADE_FAILED // 10..14
, GRADE_FAILED // 15..19
, GRADE_FAILED // 20..24
, GRADE_FAILED // 25..29
, GRADE_1 // 30..34
, GRADE_2 // 35..39
, GRADE_3 // 40..44
, GRADE_4 // 45..49
, GRADE_5 // 50..54
, GRADE_5 // 55..59
, GRADE_5 // 60..64 // Only sixty matters
};
System.out.println("Grade:"+GradeStr[points/5]+".");
If you need more granularity, make a bigger array, divide by a smaller number or skip the division altogether, and set the constants in the positions that correspond to the grades that need to be printed. This lets you avoid the conditionals altogether.
Important disclaimer: this approach works best when the number of options is small - up to a hundred or so. When your problem allows for this approach, it is the fastest approach by far. In many cases, it is also the easiest one to read.
You can use a NavigableMap, most commonly a TreeMap. The method used below is floorEntry. Quoting Javadoc:
Returns a key-value mapping associated with the greatest key less than or equal to the given key, or null if there is no such key.
Note: Your code was missing an = sign on the 29 boundary, and the points value should be an integer.
Changed to use a grade (0-5), instead of the string used in question.
// Grade boundary is lower-inclusive (grade is 0-60)
TreeMap<Integer, Integer> gradeMap = new TreeMap<>();
gradeMap.put( 0, 0); // 0–29
gradeMap.put(30, 1); // 30–34
gradeMap.put(35, 2); // 35–39
gradeMap.put(40, 3); // 40–44
gradeMap.put(45, 4); // 45–49
gradeMap.put(50, 5); // 50+
System.out.println("Type the points [0-60]: ");
int points = reader.nextInt();
reader.nextLine();
int grade = gradeMap.floorEntry(points).getValue();
System.out.println("Grade: " + grade);
If you want to test if number is between some values use logical operator AND for if statements like:
if(points>=40 && points <=45)
To get more clarity I would suggest you to make a control inversion like this:
int grade;
if(points >49){
grade=5;
}else if(points >44){
grade=4;
}else if(points >39){
grade=3;
}else if(points >34){
grade=2;
}else if(points >29){
grade=1;
}else{
grade=0;
}
System.out.println("Gr: "+grade); //grade=0 = not passed
I think you might be looking for
if( points<=44 && points>=40 )
If you want to check if a number is between two values, you would use an and in your if statement:
if (points >= 40 && points <= 44) {
System.out.println("Grade: 3.");
}
If you want to check for a range within an if statement, you can do this:
if(points >= 0 && points <= 29)
This is by using && (and) operator by combining conditions together.
But you don't really need to check for a range in any of the if-statements.
Doing what you currently have will be suffice.