I need to store multiple lines of input into the same array. The loop has to continue storing each new line into the array until a sentinel value is typed in. So far, I have this code:
while(!students.equals("zzzz") && !students.equals("ZZZZ")){
students = br.readLine();
studentInfo = students.split("\\n");
}
System.out.println (studentInfo[0]);
All this does when I type the sentinel value (either ZZZZ or zzzz) is print out zzzz at the end because it stores the sentinel value into the first array location. What am I missing? Id like to be able to type any number of lines, and access each one of those lines and manipulate the string by calling on it (studentInfo[5] or studentInfo[55]). Please help
By definition, br.readLine() will not return anything with a newline character, so this code:
students = br.readLine();
studentInfo = students.split("\\n");
will always result in studentInfo being an array of size 1, whose first (and only) element is whatever is in students.
Further, you are replacing studentInfo every loop, so it always has the last line entered, which logically must be "zzzz" or "ZZZZ".
To fix the problem, you should use a List, which can grow in size automatically (basically you should avoid using arrays).
Try this:
List<String> studentInfo = new LinkedList<>();
String student = "";
while (!student.equalsIgnoreCase("zzzz")) {
student = br.readLine();
if (!student.equalsIgnoreCase("zzzz"))
studentInfo.add(student);
}
System.out.println (studentInfo);
The while loop is a little clumsy, because the student variable must be declared outside the loop (even though it's only needed in the loop) and the condition must be repeated (otherwise your data will contain the terminating signal value).
It can be expressed better as a for loop:
for (String student = br.readLine(); !student.equalsIgnoreCase("zzzz"); student = br.readLine())
studentInfo.add(student);
Note also the use of equalsIgnoreCase() for the string comparison.
I have made slight changes to your code and added comments on how this can be done:
List<String> studentInfo = new ArrayList<>(); //use arraylist since you don't know how many students you are expecting
//read the first line
String line = ""; //add line reading logic e.g. br.readLine();
while(!line.equalsIgnoreCase("zzzz")){ //check for your sentinel value
line = br.readLine(); //read other lines
//you can add an if statment to avoid adding zzzz to the list
studentInfo.add(students);
}
System.out.println("Total students in list is: " + studentInfo.size());
System.out.println (studentInfo); //print all students in list
System.out.println (studentInfo.get(29)); //print student 30
Related
To help myself learn java, i am creating a blackjack program using a JForm GUI that include accounts that you can create and keep a running balance you use to bet on each game. I have a BlackJackApp.JForm class which is the main class. The accounts are stored in a .txt file and are read using an Account class containing readFile and writeFile methods. I created a sample txt file, named Accounts.txt, with these values:
John Doe>>1000000
Jack Black>>1
Bob Dole>>987654321
(there are no empty spaces between lines in the actual txt file)
I have a method that reads the text file and attaches these values to a HashMap. This is the code i have for the method.
public void readFile()
{
accountsMap.clear();
BufferedReader br;
try
{
br = new BufferedReader(new FileReader("Accounts.txt"));
String nextLine = br.readLine();
while(nextLine != null)
{
String lineString[] = nextLine.split(">>");
Integer accountBalance = Integer.parseInt(lineString[1]);
System.out.println(lineString[0] + " " + lineString[1] + " " +
accountBalance);
accountsMap.put(lineString[0], accountBalance);
nextLine = br.readLine();
}
br.close();
}
catch(IOException frex)
{System.out.println("An error has occurred while reading the file");}
}
This is the relevant code i have for the JForm class, with only the top portion included for reference
public class BlackjackApp extends javax.swing.JFrame {
Account a = new Account();
String account;
Integer accountBalance;
HashMap accountsMap = a.getAccountsMap();
public void fillAccountNameBox()
{
for (int i = 0; i < accountsMap.size(); i++)
{
accountNameBox.addItem((String) accountsMap.get(i));
}
}
public BlackjackApp() {
initComponents();
a.readFile();
fillAccountNameBox(); //fills comboBox component w/ list of hashMap keys
System.out.println(accountsMap.keySet());
for(int i = 0; i < accountsMap.size(); i++)
System.out.println(accountsMap.get(i));
}
The system.out.println code is for debugging. This is the output:
John Doe 1000000 1000000
Jack Black 1 1
Bob Dole 987654321 987654321
[Bob Dole, John Doe, Jack Black]
null
null
null
My question is this: why is my hashmap putting in the correct keys, but leaving their values null? The lineString array is populating correctly, and so is the Integer accountBalance, but when it comes to actually putting the key/value pairs into the hashmap, it only puts the keys in and it leaves their values null even though accountBalance is not null. Why is this? I have tried searching numerous threads for advice relating to this issue but none of their advice worked for me. There must be something that im overlooking, but as a beginner its hard for me to recognize where the problem lies.
The problem relys on the way you are printing the information.
The Map.get method expects you pass a parameter with a key, whose value you want. In the for loop, you are asking for the values attached to the keys 0, 1 and 2 - hence the null values.
Change your code to this:
for(String key : accountsMap.keySet())
System.out.println(accountsMap.get(key));
As you can see, I also changed the for loop structure to use a for-each.
Hope this helps you.
Your map contains exactly what you want it to contain. The issue is how you are accessing it.
As you have pointed out, the keys in your map are as follows:
[Bob Dole, John Doe, Jack Black]
In your final for loop, you are looking to access the values mapped to keys 0, 1 and 2. As these keys don't exist in your map, you will get null.
So I have a file which has all presidents in it - their first name, middle initial (if any), and last name.
The file needs to be read in, and a user can enter a president's name to search for it, and that president should be displayed.
I have it displaying the president if a user searches by first name or by last name, but not by both.
For example, the external file contains:
George,Washington,(1789-1797)
Franklin,D.,Roosevelt,(1933-1945)
... and so on with all the presidents
I need the user to be able to either type in the first name, the last name, or both first and last name and get the desired result (the date is irrelevant for the most part).
Tried lots of different things, but not getting there as far as displaying the president if user searches by first and last name.
Here is what I got so far:
public class NameSearch {
public static void main(String[] args) throws IOException {
try {
// read from presidents file
Scanner presidentsFile = new Scanner(new File("Presidents.txt"));
// scanner for user input
Scanner keyboard = new Scanner(System.in);
// create array list of each line in presidents file
ArrayList<String> presidentsArrayList = new ArrayList<String>();
// prompt user to enter a string to see if it matches with a president's name
System.out.println("Enter a search string of letters to find a president match: ");
// store user input
String userInput = keyboard.nextLine();
// add president file info to array list linesInPresidentFile
while (presidentsFile.hasNextLine()) {
presidentsArrayList.add(presidentsFile.nextLine());
} // end while loop
String presidentNamesArray[] = presidentsArrayList.toArray(new String[presidentsArrayList.size()]);
String results = searchArray(presidentNamesArray, userInput);
//System.out.println("\nThe presidents who have \"" + userInput + "\" as part of their name are: ");
} catch (FileNotFoundException ex) {
// print out error (if any) to screen
System.out.println(ex.toString());
} // end catch block
} // end main
// method to search for a specific value in an array
public static String searchArray(String array[], String value) {
for (int i = 0; i < array.length; i++) {
if (array[i].toLowerCase().contains(value.toLowerCase())) {
String splitter[] = array[i].split(" ,");
System.out.println(Arrays.toString(splitter));
}
}
return Arrays.toString(array);
}
}
There is another way in which I might have implemented this.Read the file inputs and stored them as objects (class with lname, fname and year perhaps). In this way you can search for lname from user input, match it up with its corresponding fname (as same objects). The creation can be done once and searching can be done in a while loop implementing users consent of continuing the search.
//define your class like this:
static int i; //to keep a track of number of objects
public class dummy{
string fname;
string lname;
string year;
};
while the file content exists:
read the line
dummy dobj[i++] = new dummy();//allocate memory for the object
split the different parameters (fname, lname, year) from the read line
put these read parameters into the object
dobj[i].fname = first;
dobj[i].lname = second;
dobj[i].year = y;
//ask your user to enter the query in a specified format
//if he enters lname, compare your input to all the object's lname, and so on
//in case of lname && fname, compare your input to the lname first and then check for the corresponding objects fname, if they match.. display
Actually, there are many ways in which you can achieve what you wish to program. You can ask use the array list indices to solve it. If you take in the input from the user in a particular format, you can map it to the index in that list. Further, if you want to use first name and last name together, you may use these index representing the first and last name to come from same list.
The reason you may have problems searching by both first and last names is because you have to match your input exactly (ignoring case of course). What I mean is if you use George Washington as input, your program will not find a match for the George,Washington,(1789-1797) line. This is because your program treats George Washington as one string. Note: the input is missing the comma, so it will not be considered a substring of George,Washington,(1789-1797). If you used George,Washington as your input string, then your program would print the George Washington line. Your program just searches if the input string is a substring of any of the lines in your file. It does not search for a first name or last name specifically. If you used in as your input string, then you would get a match for both George Washington and Franklin D. Roosevelt.What you could do is take your input data and split it and search for each of the terms. You can either accept lines that match all of the terms provided, or at least one of the terms provided.
public static String searchArray(String array[], String value) {
// Uses both blank spaces and commas as delimiters
String[] terms = value.toLowerCase().Split("[ ,]");
for (int i = 0; i < array.length; i++) {
String line = array[i].toLowerCase();
boolean printIfAllMatch = true;
boolean printIfAtLeastOneMatches = false;
for(int j = 0 ; j < terms.length; j++) {
// Check that all terms are contained in the line
printIfAllMatch &= line.Contains(terms[j]);
// Check that at least one term is in the line
printIfAtLeastOneMatches |= line.Contains(terms[j]);
}
String splitter[] = array[i].split(" ,");
if (printIfAllMatch) {
System.out.println(Arrays.toString(splitter));
}
if(printIfAtLeastOneMatches) {
System.out.println(Arrays.toString(splitter));
}
}
//I'm not sure why you're returning the original array as a string
//I would think it would make more sense to return an Array of filtered data.
return Arrays.toString(array);
}
This does not take name ordering into account. If that's what you're going for, then I would suggest making a class and parsing each line in the file as an new object and trying to match the first term provided with the first name and second term provided with the last name, or something to that effect.
I am trying to use scanner to read in several lines of input at a time. I reckon that there is something wrong with either the way I use the loop, or the way I read in information. Nothing was stored in the output array. I commented my question in the code. Can someone please help? Thank you!
Scanner c = new Scanner (System.in);
while (c.hasNextLine()){
ArrayList <Integer> record= new ArrayList <Integer> (); // next time the while loop runs, I expect the list record to be initialized again
String numbers = c.nextLine();
int n = Integer.parseInt(numbers);
for (int i=0; i<n; i++){
String info = c.nextLine();//then read the following n lines use for loop
int length = info.length(); //get the length of each line
record.add(length);
}
putRecordinArray(record);//some other function to process each record(a block of several lines processed each time by the while loop)
}
//here I tried to print out the array A generated by other function, but nothing was stored.
}
Your Arraylist name is records but you are calling it with record which is records without the 's'. You have to add the 's'.
example of one of your calling statements.
record.add(length);
change to:
records.add(length);
also:
putRecordinArray(record);
change to:
putRecordinArray(records);
Hope this helps.
I am using 'java.util.Scanner' to read and scan for keywords and want to print the previous 5 lines and next 5 lines of the encountered keyword, below is my code
ArrayList<String> keywords = new ArrayList<String>();
keywords.add("ERROR");
keywords.add("EXCEPTION");
java.io.File file = new java.io.File(LOG_FILE);
Scanner input = null;
try {
input = new Scanner(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
int count = 0;
String previousLine = null;
while(input.hasNext()){
String line = input.nextLine();
for(String keyword : keywords){
if(line.contains(keyword)){
//print prev 5 lines
system.out.println(previousLine); // this will print only last previous line ( i need last 5 previous lines)
???
//print next 5 lines
system.out.println(input.nextLine());
system.out.println(input.nextLine());
system.out.println(input.nextLine());
system.out.println(input.nextLine());
system.out.println(input.nextLine());
}
previousLine = line;
}
any pointers to print previous 5 lines..?
any pointers to print previous 5 lines..?
Save them in an Dequeue<String> such as a LinkedList<String> for its "First In First Out (FIFO)" behavior.
Either that or use 5 variables or an array of 5 Strings, manually move Strings from one slot or variable to another, and then print them.
If you use Dequeue/LinkedList, use the Dequeue's addFirst(...) method to add a new String to the beginning and removeLast() to remove the list's last String (if its size is > 5). Iterate through the LinkedList to get the current Strings it contains.
Other suggestions:
Your Scanner's check scanner.hasNextXXX() method should match the get method, scanner.nextXXX(). So you should check for hasNextLine() if you're going to call nextLine(). Otherwise you risk problems.
Please try to post real code here in your questions, not sort-of, will never compile code. i.e., system.out.println vs System.out.println. I know it's a little thing, but it means a lot when others try to play with your code.
Use ArrayList's contains(...) method to get rid of that for loop.
e.g.,
LinkedList<String> fivePrevLines = new LinkedList<>();
java.io.File file = new java.io.File(LOG_FILE);
Scanner input = null;
try {
input = new Scanner(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
while (input.hasNextLine()) {
String line = input.nextLine();
if (keywords.contains(line)) {
System.out.println("keyword found!");
for (String prevLine : fivePrevLines) {
System.out.println(prevLine);
}
} else {
fivePrevLines.addFirst(line);
if (fivePrevLines.size() > 5) {
fivePrevLines.removeLast();
}
}
}
if (input != null) {
input.close();
}
Edit
You state in comment:
ok i ran small test program to see if the contains(...) method works ...<unreadable unformatted code>... and this returned keyword not found...!
It's all how you use it. The contains(...) method works to check if a Collection contains another object. It won't work if you feed it a huge String that may or may not use one of the Strings in the collection, but will work on the individual Strings that comprise the larger String. For example:
ArrayList<String> temp = new ArrayList<String>();
temp.add("error");
temp.add("exception");
String s = "Internal Exception: org.apache.tomcat.dbcp.dbcp.SQLNestedException: Cannot get a connection, pool error Timeout waiting for idle object";
String[] tokens = s.split("[\\s\\.:,]+");
for (String token : tokens) {
if (temp.contains(token.toLowerCase())) {
System.out.println("keyword found: " + token);
} else {
System.out.println("keyword not found: " + token);
}
}
Also, you will want to avoid posting code in comments since they don't retain their formatting and are unreadable and untestable. Instead edit your original question and post a comment to alert us to the edit.
Edit 2
As per dspyz:
For stacks and queues, when there isn't any significant functionality/performance reason to use one over the other, you should default to ArrayDeque rather than LinkedList. It's generally faster, takes up less memory, and requires less garbage collection.
If your file is small (< a million lines) you are way better off just copying the lines into an ArrayList and then getting the next and previous 5 lines using random access into the array.
Sometimes the best solution is just plain brute force.
Your code is going to get tricky if you have two keyword hits inside your +-5 line window. Let's say you have hits two lines apart. Do you dump two 10-line windows? One 12-line window?
Random access will make implementing this stuff way easier.
I am trying to display statistics from a simple text file using arrays in Java. I know what I am supposed to do, but I don't really how how to code it. So can anybody show me a sample code on how to do it.
So let's say the text file is called gameranking.txt, that contains the following information (This is a simple txt file to use as an example):
Game Event, 1st place, second place, third place, fourth place
World of Warcraft, John, Michael, Bill, Chris
Call of Duty, Michael, Chris, John, Bill
League of Legends, John, Chris, Bill, Michael.
My goal is to display stats such as how many first places, second places.. each individual won in a table like the following
Placement First place, second, third, fourth
John 2 0 1 0
Chris 0 2 0 1
etc...
My thought:
First, I would read the gameranking.txt and stores it to "input". Then I can use the while loop to read each line and store each line into a string called "line", afterward, I would use the array method "split" to pull out each string and store them into individual array. Afterward, I would count which placement each individual won and display them into a neat table using printf.
My first problem is I don't know how to create the arrays for this data. Do I first need to read through the file and see how many strings are in each row and column, then create the array table accordingly? Or can I store each string in an array as I read them?
The pseudocode that I have right now is the following.
Count how many rows are there and store it in row
Count how many column are there and store it in column
Create an array
String [] [] gameranking = new String [row] [column]
Next read the text file and store the info into the arrays
using:
while (input.hasNextLine) {
String line = input.nextLine();
while (line.hasNext()) {
Use line.split to pull out each string
first string = event and store it into the array
second string = first place
third string =......
Somewhere in the code, I need to count the placement....
Can somebody please show me how I should go about doing this?
I am not going to write the full program, but I will try to tackle each question and give you a simple suggestion:
Reading the initial file, you can get each line and store it in a string using a BufferedReader (or if you like, use a LineNumberReader)
BufferedReader br = new BufferedReader(new FileReader(file));
String strLine;
while ((strLine = br.readLine()) != null) {
......Do stuff....
}
At that point, in the while loop you will go through the string (since it comma delimited, you can use that to seperate each section). for each substring you can
a) compare it with first, second, third, fourth to get placement.
b) if its not any of those, then it could either be a game name or a user name
You can figure that out by position or nth substring (ie if this is the 5th substring, its likely to be the first game name. since you have 4 players, the next game name will be the 10th substring, etc.). Do note, I ignored "Game event" as that's not part of the pattern. You can use split to do this or a number of other options, rather than try to explain that I will give you a link to a tutorial I found:
http://pages.cs.wisc.edu/~hasti/cs302/examples/Parsing/parseString.html
As for tabulating results, Basically you can get an int array for each player which keeps track of their 1st, 2nd, 3rd, awards etc.
int[] Bob = new int[4]; //where 0 denotes # of 1st awards, etc.
int[] Jane = new int[4]; //where 0 denotes # of 1st awards, etc.
Showing the table is a matter of organizing the data and using a JTable in a GUI:
http://docs.oracle.com/javase/tutorial/uiswing/components/table.html
Alrighty...Here is what I wrote up, I am sure there is a cleaner and faster way, but this should give you an idea:
String[] Contestants = {"Bob","Bill","Chris","John","Michael"};
int[][] contPlace=new int[Contestants.length][4];
String file = "test.txt";
public FileParsing() throws Exception {
Arrays.fill(contPlace[0], 0);
Arrays.fill(contPlace[1], 0);
Arrays.fill(contPlace[2], 0);
Arrays.fill(contPlace[3], 0);
BufferedReader br = new BufferedReader(new FileReader(file));
String strLine;
while((strLine=br.readLine())!=null){
String[] line = strLine.split(",");
System.out.println(line[0]+"/"+line[1]+"/"+line[2]+"/"+line[3]+"/"+line[4]);
if(line[0].equals("Game Event")){
//line[1]==1st place;
//line[2]==2nd place;
//line[3]==3rd place;
}else{//we know we are on a game line, so we can just pick the names
for(int i=0;i<line.length;i++){
for(int j=0;j<Contestants.length;j++){
if(line[i].trim().equals(Contestants[j])){
System.out.println("j="+j+"i="+i+Contestants[j]);
contPlace[j][i-1]++; //i-1 because 1st substring is the game name
}
}
}
}
}
//Now how to get contestants out of the 2d array
System.out.println("Placement First Second Third Fourth");
System.out.println(Contestants[0]+" "+contPlace[0][0]+" "+contPlace[0][1]+" "+contPlace[0][2]+" "+contPlace[0][3]);
System.out.println(Contestants[1]+" "+contPlace[1][0]+" "+contPlace[1][1]+" "+contPlace[1][2]+" "+contPlace[1][3]);
System.out.println(Contestants[2]+" "+contPlace[2][0]+" "+contPlace[2][1]+" "+contPlace[2][2]+" "+contPlace[2][3]);
System.out.println(Contestants[3]+" "+contPlace[3][0]+" "+contPlace[3][1]+" "+contPlace[3][2]+" "+contPlace[3][3]);
System.out.println(Contestants[4]+" "+contPlace[4][0]+" "+contPlace[4][1]+" "+contPlace[4][2]+" "+contPlace[4][3]);
}
If you need to populate the contestants array or keep track of the games, you will have to insert appropriate code. Also note, using this 2-d array method is probably not best if you want to do anything other than display them. You should be able to take my code, add a main, and see it run.
Since it's a text file, use Scanner class.
It can be customized so that you can read the contents line-by-line, word-by-word, or customized delimiter.
The readfromfile method reads a plain text file one line at a time.
public static void readfromfile(String fileName) {
try {
Scanner scanner = new Scanner(new File(fileName));
scanner.useDelimiter(",");
System.out.println(scanner.next()); //instead of printing, take each word and store them in string array
scanner.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
This will get you started.