Printing out line from CSV file that contains user input - - java

I have a program that allows the user to input observations into a CSV file and save them.
I want to be able to read the file and only print out observations that the user searches for. (ex. user types in "planet" and all lines containing planet are printed out. My current code prints out the whole file, and not just the specified lines. I'm having trouble setting up a logical statement to do this.
Here's my code:
void findbird() throws IOException{
Scanner input = new Scanner(System.in);
System.out.println("Please enter the type of bird you wish to search for");
String bird;
bird = input.next();
System.out.println("All observations of " + bird + "s:");
BufferedReader br = new BufferedReader(new FileReader("birdobservations.txt"));
String dataRow = br.readLine();
boolean contains = bird.toLowerCase().contains(dataRow.toLowerCase());
while (dataRow != null){
String[] dataArray = dataRow.split(",");
for (String item:dataArray) {
if(contains = true){
System.out.print(item + "\t");
}else{
System.out.println("No observations of " + bird + " found!");
}
}
System.out.println();
dataRow = br.readLine();
}
br.close();
System.out.println();
menu();
}
My output currently looks like this:
Please enter the type of bird you wish to search for
Crow
All observations of Crows: Crow X Bergen May2015
Woodpecker M Oslo July2012
Hummingbird M Kaupanger December2015
Whereas I only want to print out:
Crow X Bergen May2015

There are a few problems.... the two most glaring are:
boolean contains = bird.toLowerCase().contains(dataRow.toLowerCase()); should surely be the other way around (dataRow...contains(...bird...))
You never reset the boolean variable contains so that it will print everything after it first is set to true... there has to be a contains = false somewhere
In general, you should probably have a loop that looks like:
String dataRow = null;
while ( (dataRow = scanner.readLine() ) != null) {
....
}
That way you do not need to do the silly readLine outside the loop as well, which makes your code cumbersome.
Once you have fixed up these code issues then come back again with an edited question.

This is the problem code
String dataRow = br.readLine();
boolean contains = bird.toLowerCase().contains(dataRow.toLowerCase());
while (dataRow != null){
String[] dataArray = dataRow.split(",");
for (String item:dataArray) {
if(contains = true){
System.out.print(item + "\t");
}else{
System.out.println("No observations of " + bird + " found!");
}
}
Change it to
while((dataRow = br.readline())!= null)
{
//And now you get value of contain and then check if contain == true and add other piece of code
}

Your contains check is the wrong way around. The format is string.contains(substring).
contains should be moved inside the loop, otherwise you just set it once in the beginning, instead of for each row.
contains = true should be contains == true or simply contains. contains = true is assignment and will always return true, regardless of the value contains had.
Move the contains check outside the for-loop, otherwise it will print a message for each column in the row, not just once per row.
System.out.println(); will cause blank lines to be printed, if this is unwanted (it probably is), it should be removed.
Code:
while (dataRow != null){
boolean contains = dataRow.toLowerCase().contains(bird.toLowerCase());
String[] dataArray = dataRow.split(",");
if(contains){
for (String item:dataArray) {
System.out.print(item + "\t");
}
}
else
{
System.out.println("No observations of " + bird + " found!");
}
dataRow = br.readLine();
}

You have your logic backwards. Do:
boolean contains = dataRow.toLowerCase().contains(bird.toLowerCase());
Also, the fact that you have:
if(contains = true){
System.out.print(item + "\t");
}else{
System.out.println("No observations of " + bird + " found!");
}
means that contains will always be true, because you are assigning true to contains. You need to do:
if(contains == true){
System.out.print(item + "\t");
}else{
System.out.println("No observations of " + bird + " found!");
}

Related

Java for loop running both true and false conditions

I refactored a working project to practice creating callable methods when I broke the app. This app includes a simple String array with a method that matches user input with the array and prints the element name and index.
If I don't include a break at the end of the if else statements the app can match valid input but runs both if and else statements. It actually prints the if statement in the order of the index and prints the else output the number of times as the length of the array. In the attached pic, the input was index 0. if statement output In the pic index 0 was matched and printed with the number of else outputs as in the array. It seems the else statement is reading the array length.
If I add the break, the app only recognizes index 0 and will run the if statement as expected, but also runs the else statement. But only prints out if else output once. I hope this is clear. Trainers have simply said it is impossible to for a for loop to print of which I understand, yet I'm having a different experience.
Here is the code:
import java.util.Scanner;
public class Main {
static Scanner scan = new Scanner(System.in);
public static void main(String[] args) {
System.out.println("What are you looking for? ");
//String product = scan.nextLine();
String[] aisles = {"apples", "bananas", "candy", "chocolate", "coffee", "tea"};
searchProduct(aisles);
}
public static void searchProduct(String[] aisles) {
String product = scan.nextLine();
for (int i = 0; i < aisles.length; i++) {
if (product.equals(aisles[i])) {
System.out.println("We have " + aisles[i] + " in aisle " + i);
} else {
System.out.println("Sorry we do not have that product");
}
}
}
}
I expect to match valid user input and run the if statement or run the else statement.
Here is a suggestion.
Change your method to return an int (aisle if the product exists or -1 if not).
Don't do any I/O in the method. Just pass the target of the search as an argument.
String[] aisles = {
"apples","bananas","candy","chocolate","coffee","tea"
};
System.out.println("What are you looking for? ");
String product = scan.nextLine();
int aisle = searchProduct(product, aisles);
if (aisle >= 0) {
System.out.println("We have " + product + " in aisle " + aisle);
} else {
System.out.println("Sorry we do not have that product");
}
public static int searchProduct(String product, String[] aisles) {
for (int aisle = 0; aisle < aisles.length; aisle++) {
if (product.equals(aisles[aisle])) {
return aisle;
}
}
return -1;
}

When parsing text file input does not move to next line

I am looking for a little help. I have done quite a bit of googling with little success.
I am new to programming and am sure this is a silly oversight on my part.
The below code is intended to read through a .txt document that is tab delimited. The .txt file is formatted into six columns. Currently, as I move through the file I parse the string to the appropriate value type and assign it to its respective variable. Code is here:
try {
s = new Scanner(new BufferedReader(new FileReader(file))).useDelimiter("\t");
while (s.hasNextLine()) {
group = Integer.parseInt(s.next());
death = Integer.parseInt(s.next());
name = s.next();
sex = s.next();
age = Integer.parseInt(s.next());
fare = Double.parseDouble(s.next());
System.out.println("Class = " + group); // Test that value is being assigned
System.out.println("Death = " + death); // Test that value is being assigned
System.out.println("Name = " + name); // Test that value is being assigned
System.out.println("Gender = " + sex); // Test that value is being assigned
System.out.println("Age = " + age); // Test that value is being assigned
System.out.println("Fare = " + fare); // Test that value is being assigned
}
} finally {
if (s != null) {
s.close();
}
}
When I reach the last column of the first row, the variable fare is set to row 1 column 6 AND row 2 column 1. For some reason the line break is not triggering the while loop to restart.
Can anyone help me understand why the while loop does not restart at the end of the line?
File looks like this:
1 5 Bryan male 25 211.3375
1 2 Jimmy male 22 151.5500
There is about 1200 lines of this. When running this loop I get the below error when attempting to set fare = 211.3375 at the end of the first row. For some reason, the line break isn't resetting the loop. I can only assume that the line break is not interpreted as a tab but do not know how to correct this.
Exception in thread "main" java.lang.NumberFormatException: For input string: "211.3375
1"
You're checking Scanner#hasNextLine() but then reading multiple Scanner#next(), a dangerous thing to do. I suggest if you check for next line, you should read next line, and then parse through that line.
e.g.,
while (s.hasNextLine()) {
String line = s.nextLine();
Scanner lineScanner = new Scanner(line);
group = lineScanner.nextInt();
death = lineScanner.nextInt();
name = lineScanner.next();
sex = lineScanner.next();
age = lineScanner.nextInt();
fare = lineScanner.nextDouble();
lineScanner.close();
System.out.println("Class = " + group); // Test that value is being assigned
System.out.println("Death = " + death); // Test that value is being assigned
System.out.println("Name = " + name); // Test that value is being assigned
System.out.println("Gender = " + sex); // Test that value is being assigned
System.out.println("Age = " + age); // Test that value is being assigned
System.out.println("Fare = " + fare); // Test that value is being assigned
}
But even this is somewhat dangerous because I'm calling Scanner#next...() without first checking. And so perhaps safer would be to do
String[] tokens = line.split("\\s+");
Then count the tokens length to be sure that it's right, and then parse each individual token that needs parsing to numeric type.
Or you could do something like:
while (s.hasNextLine()) {
String line = s.nextLine();
Scanner lineScanner = new Scanner(line);
if (lineScanner.hasNextInt()) {
group = lineScanner.nextInt();
}
if (lineScanner.hasNextInt()) {
death = lineScanner.nextInt();
}
if (lineScanner.hasNext()) {
name = lineScanner.next();
}
if (lineScanner.hasNext()) {
sex = lineScanner.next();
}
if (lineScanner.hasNextInt()) {
age = lineScanner.nextInt();
}
if (lineScanner.hasNextDouble()) {
fare = lineScanner.nextDouble();
}
lineScanner.close();
System.out.println("Class = " + group); // Test that value is being assigned
System.out.println("Death = " + death); // Test that value is being assigned
System.out.println("Name = " + name); // Test that value is being assigned
System.out.println("Gender = " + sex); // Test that value is being assigned
System.out.println("Age = " + age); // Test that value is being assigned
System.out.println("Fare = " + fare); // Test that value is being assigned
}
or use try/catch blocks to check for bad files.

Using split() and checking for a 2nd element

I have code for a Binary Search Tree that will accept user input such as
insert 3 and it will call the insert function on 3. When I try to call a function that requires no arguments like my traverse function it will give an out of bounds error unless the user input is traverse 0 I want to call it by using just traverse, here is my code:
public static void main(String[] args)
{
int quit = 0;
BinarySearchTree bst = new BinarySearchTree();
Scanner in = new Scanner(System.in);
//Accept user input and call funtions
while(quit != 1)
{
System.out.print("\nEnter the instructions to perform (type quit when done):");
String input = in.nextLine();
String[] instruction = input.split(" ");
String function = instruction[0].toLowerCase();
String parameter = instruction[1];
//What to do with user input
if(function.equals("insert"))// for insert
{
int key = Integer.parseInt(parameter);
bst.insert(key);
System.out.println(parameter + " was inserted successfully!");
}
else if(function.equals("delete"))// for delete
{
int key = Integer.parseInt(parameter);
if(bst.delete(key) == true)
System.out.println(parameter + " was deleted successfully!");
else
System.out.println(parameter + " does not exist.");
bst.delete(key);
}
else if(function.equals("search"))// for search
{
int key = Integer.parseInt(parameter);
if(bst.search(key) == true)
System.out.println(parameter + " was found!");
else
System.out.println(parameter + " not found.");
bst.search(key);
}
else if(function.equals("traverse"))// for traverse
{
bst.traverse(BinarySearchTree.root);
}
}
}//end main
Your problem occurs when you try to assign instruction[1] to parameter. If there is no space character in your input string then the split method will return an array of length 1 and you will get an out of range exception when you try to access the second element.
The solution is:
if (input.equals("traverse")) {
...
} else {
String[] instructions = input.split(" ");
assert instruction.length == 2;
String function = instruction[0].toLowerCase();
int key = Integer.parseInt(instruction[1]);
...
}
There are better ways to model commands. Ideally you'd use a command pattern rather than if statements. But if you don't want to go to that trouble you should at least consider using patterns to make the parsing more robust.
Pattern commandPattern = Pattern.compile("(traverse|search|delete|insert) *(\\d*)");
Matcher matcher = commandPattern.match(in.nextLine());
if (!matcher.matches()) {
System.out.println("Illegal command. Try again.");
matcher = commandPattern.match(in.nextLine());
}
switch (matcher.group(1).toLowerCase()) {
case "traverse":
bst.traverse(root);
break;
case "delete":
int deleteKey = Integer.parseInt(matcher.group(2));
if (bst.delete(deleteKey)) {
...

Using one text file to search through another text file

So I've been trying to get this to work for some time. Let me preface this by saying that I'm not a programmer. It's more a of a hobby that I've recently taken up. I've been trying to get 2 text files to search through each other line by line. i.e. One has a bunch of words (around 10, one per line), and the other has many more (close to 500) also one per line. What I would like is for my program to say how many times each of the words in the smaller text file appears in the larger one. What i have so far is:
import java.util.Scanner;
import java.io.File;
import java.util.regex.Pattern;
public class StringSearch
{
public static void main (String args[]) throws java.io.IOException
{
int tot = 0;
Scanner scan = null;
Scanner scan2 = null;
String str = null;
String str2 = null;
File file = new File("C:\\sample2.txt");
File file2 = new File("C:\\sample3.txt");
scan = new Scanner(file);
scan2 = new Scanner(file2);
while (scan.hasNextLine())
{
str = scan.nextLine();
tot = 0;
while (scan2.hasNextLine())
{
str2 = scan2.nextLine();
if(str.equals(str2))
{
tot++;
}
}
System.out.println("The String = " + str + " and it occurred " + tot + " times");
}
}
}
Not sure why this isnt working. It reads the first word in the first text file fine and counts how many times it appears in the second one, but then it just stop and doesnt move on the the second word in the first file. I hope that makes sense. Something is wrong with the second while loop I think, but I have no idea what.
So, any help would be greatly appreciated. I'm hoping to get this to work and move on to more complicated projects in the future. Gotta start somewhere right?
Cheers Guys
The issue you are running across is that you are using a scanner within a scanner. The way that you currently have your scanners nested, it causes one scanner to completely read through its entire text file for the first word, but after that first run through, it has already read the entire file and will never return true for scan2.hasNextLine().
A better way to achieve what you want is what remyabel stated. You should create an array that will contain all of the words from your small file that will be iterated through every time you go through a word in your other file. You would also need to create something to keep track of how many times each word is hit so you could use something like a hashmap.
It would look something along the lines of this:
Scanner scan = null;
Scanner scan2 = null;
String str = null;
String str2 = null;
File file = new File("C:\\sample2.txt");
File file2 = new File("C:\\sample3.txt");
scan = new Scanner(file);
scan2 = new Scanner(file2);
//Will contain all of your words to check against
ArrayList<String> dictionary = new ArrayList<String>();
//Contains the number of times each word is hit
HashMap<String,Integer> hits = new HashMap<String, Integer>();
while(scan.hasNextLine())
{
str = scan.nextLine();
dictionary.add(str);
hits.put(str, 0);
}
while (scan2.hasNextLine())
{
str2 = scan2.nextLine();
for(String str: dictionary)
{
if(str.equals(str2))
{
hits.put(str, hits.get(str) + 1);
}
}
}
for(String str: dictionary)
{
System.out.println("The String = " + str + " and it occurred " + hits.get(str) + " times");
}
}
Create a buffered reader and read the file into a map of <String, Integer>:
String filename = args[0];
BufferedReader words = new BufferedReader(new FileReader(FILENAME));
Map<String, Integer>m = new HashMap<String, Integer>();
for(String word: words.readLine()){
if(word!=null && word.trim().length()>0) {
m.add(String, 0);
}
}
Then read the words list and increment the map's value each time you find one:
String filename = args[1];
BufferedReader listOfWords = new BufferedReader(new FileReader(FILENAME2));
for(String word: listOfWords.readLine()){
if(word!=null && word.trim().length()>0) {
if(m.get(word)!=null){
m.add(word, m.get(word) + 1);
}
}
}
Then print the results:
for(String word: map.keys()){
if(map.get(word)>0){
System.out.println("The String = " + word + " occurred " + map.get(word) + " times");
}
}
Your approach with using nested loops would scan the second file for every word in the first one. This would be highly inefficient. I suggest loading the first file in a HashMap.
Not only this would leverage on quick lookups, you could update the count of occurrence easily as well. Not to mention, you would be scanning the second file just once and any duplicates that you might have in the first one would automatically be ignored (as the results would be the same).
Map<String, Integer> wordCounts = new HashMap<String, Integer>();
Scanner scanner = new Scanner("one\nfive\nten");
while (scanner.hasNextLine()) {
wordCounts.put(scanner.nextLine(), 0);
}
scanner.close();
scanner = new Scanner("one\n" + // 1 time
"two\nthree\nfour\n" +
"five\nfive\n" + // 2 times
"six\nseven\neight\nnine\n" +
"ten\nten\nten"); // 3 times
while (scanner.hasNextLine()) {
String word = scanner.nextLine();
Integer integer = wordCounts.get(word);
if (integer != null) {
wordCounts.put(word, ++integer);
}
}
scanner.close();
for (String word : wordCounts.keySet()) {
int count = wordCounts.get(word);
if (count > 0) {
System.out.println("'" + word + "' occurs " + count + " times.");
}
}
Output :
'ten' occurs 3 times.
'five' occurs 2 times.
'one' occurs 1 times.
Its just a simple logic issue..
add following statement below System.out.println
scan2 = new Scanner(file2);

delete method with string arrays

I'm trying to write a method that will delete a CD (CD include artist name, album title, and track titles).. there are 5 CDs and I want to delete on of them... this is what the method should do :
void delete() will 1) ask the user for an artist and title, then attempt to find a CD with
matching artist and title, 2) display the CD if found, or tell the user it was not found, and 3)
if found, ask the user to confirm deletion (this needs keyboard input), deleting the CD
entry if the user confirms.
and this is my code:
public void delete() {
Scanner deleteInput = new Scanner(System.in);
System.out.println("Which artist you would like to delete? ");
System.out.println("Enter artist name and title to be deleted:");
String artist = deleteInput.nextLine();
String title = deleteInput.nextLine();
for (int i = 0; i <= CDlist.length - 1; i++) {
if ((CDlist[i].getArtist().equals(artist))
&& (CDlist[i].getTitle().equals(title))) {
System.out.println("Found: " + CDlist[i].getArtist() + " "
+ CDlist[i].getTitle());
if (CDlist[i] == null) {
continue;
}
System.out.println("Would you like to delete it? Yes 0 No 1");
if (deleteInput.nextInt() == 1) {
CDlist[i] = null;
cdnum--;
}
} else {
System.out.println("CD not found in the list.");
}
}
my problem is that when I type the correct Artist and Title to be removed I'm getting output as CD not found ( but it should say found and then removes it) how do I fix this please?
This is what I meant. Also you have an extra { in your first if right after the for loop starts. I hope that isn't causing an issue.
I have added the ignore case part based on some comments.
public void delete() {
Scanner deleteInput = new Scanner(System.in);
System.out.println("Which artist you would like to delete? ");
System.out.println("Enter artist name and title to be deleted:");
String artist = deleteInput.nextLine();
String title = deleteInput.nextLine();
boolean found = false;
int idx = -1;
System.err.println("DEBUG: Input Data");
System.err.println("Artist Name: "+artist+" Length of String: "+artist.length());
System.err.println("Title: "+artist+" Length of String: "+title.length());
System.err.println();
for (int i = 0; i <= CDlist.length - 1; i++) {
if (CDlist[i]!=null) {
System.err.println("DEBUG: Checking Index "+i);
System.err.println("Artist Name: "+CDlist[i].getArtist()+" Length of String: "+CDlist[i].getArtist().length() + " Matches: "+CDlist[i].getArtist().equalsIgnoreCase(artist));
System.err.println("Title: "+CDlist[i].getTitle()+" Length of String: "+CDlist[i].getTitle().length() + " Matches: "+CDlist[i].getTitle().equalsIgnoreCase(title));
System.err.println();
}
if (CDlist[i]!=null && CDlist[i].getArtist().equalsIgnoreCase(artist) && CDlist[i].getTitle().equalsIgnoreCase(title)) {
System.out.println("Found: " + CDlist[i].getArtist() + " " + CDlist[i].getTitle());
found = true;
idx = i;
break;
}
}
if (found) {
System.out.println("Would you like to delete it? Yes 0 No 1");
if (Integer.parseInt(deleteInput.nextLine()) == 1) {
CDlist[idx] = null;
//I am assuming cdnum is a variable of the class that can be accessed.
cdnum--;
}
} else {
System.out.println("CD not found in the list.");
}
}
Note: You need not put CDlist[i] in an if statement on its own you can just merge into the other statement. This can be done because java looks at things left-> right and so it'll check for null before trying to do anything. You can put it on its own but you'll need to put it BEFORE your first if statement.

Categories