1

The first assignment of my algorithms class is that I have to create a program that reads a series of book titles from a provided csv file, sorts them, and then prints them out. The assignment has very specific parameters, and one of them is that I have to create a static List getList(String file) method. The specifics of what this method entails are as follows:

"The method getList should readin the data from the csv file book.csv. If a line doesn’t follow the pattern title,author,year then a message should be written to the standard error stream (see sample output) The program should continue reading in the next line. NO exception should be thrown ."

I don't have much experience with the usage of List, ArrayList, or reading in files, so as you can guess this is very difficult for me. Here's what I have so far for the method:

public static List<Book> getList(String file)
{
    List<Book> list = new ArrayList<Book>();

    return list;
}

Currently, my best guess is to make a for loop and instantiate a new Book object into the List using i as the index, but I wouldn't know how high to set the loop, as I don't have any method to tell the program how, say, many lines there are in the csv. I also wouldn't know how to get it to differentiate each book's title, author, and year in the csv.

Sorry for the long-winded question. I'd appreciate any help. Thanks.

  • The CSV file is just a text file. You can either use a CSV parser, OR you can just read in each line from the file, use `String#split` to break out each part, do a validation for the order, create a `Book` object from them (if they pass) and add it to an `ArrayList`. There are MANY examples of each part of that on this site and just doing a Google search. – Ascalonian Jan 20 '15 at 19:35
  • [Here's](http://stackoverflow.com/a/22074145/3315914) an example of reading a file line by line. You can make a constructor for creating a new Book from a String, using `String.split(",")`. – rpax Jan 20 '15 at 19:38
  • Follow up question... will the file contain quoted strings that could possibly also contain a comma? For example `"Awesome Book, The"` ? – Ascalonian Jan 20 '15 at 19:42

2 Answers2

2

The best way to do this, would be to read the file line by line, and check if the format of the line is correct. If it is correct, add a new object to the list with the details in the line, otherwise write your error message and continue.

You can read your file using a BufferedReader. They can read line by line by doing the following:

        BufferedReader br = new BufferedReader(new FileReader(file));
        String line;

        while ((line = br.readLine()) != null) {
            // do something with the line here

        }
        br.close();

Now that you have the lines, you need to verify they are in the correct format. A simple method to do this, is to split the line on commas (since it is a csv file), and check that it has at least 3 elements in the array. You can do so with the String.split(regex) method.

String[] bookDetails = line.split(",");

This would populate the array with the fields from your file. So for example, if the first line was one,two,three, then the array would be ["one","two","three"].

Now you have the values from the line, but you need to verify that it is in the correct format. Since your post specified that it should have 3 fields, we can check this by checking the length of the array we got above. If the length is less than 3, we should output some error message and skip that line.

            if(bookDetails.length<3){ //title,author,year
                System.err.println("Some error message here"); // output error msg
                continue; // skip this line as the format is corrupted
            }

Finally, since we have read and verified that the information we need is there, and is in the valid format. We can create a new object and add it to the list. We will use the Integer wrapper built into Java to parse the year into a primitive int type for the Book class constructor. The Integer has a function Integer.parseInt(String s) that will parse a String into an int value.

list.add(new Book(bookDetails[0], bookDetails[1], Integer.parseInt(bookDetails[2])));

Hopefully this helps you out, and answers your question. A full method of what we did could be the following:

public static List<Book> getList(String file) {
    List<Book> list = new ArrayList<Book>();

    try {
        BufferedReader br = new BufferedReader(new FileReader(file));
        String line;

        while ((line = br.readLine()) != null) {
            String[] bookDetails = line.split(",");
            if (bookDetails.length < 3) { // title,author,year
                System.err.println("Some error message here");
                continue;
            }

            list.add(new Book(bookDetails[0], bookDetails[1], Integer.parseInt(bookDetails[2])));

        }
        br.close();
    } catch (IOException e) {
        e.printStackTrace();
    }

    return list;
}

And if you would like to test this, a main method can be made with the following code (this is how I tested it).

public static void main(String[] args) {
    String file = "books.csv";
    List<Book> books = getList(file);
    for(Book b : books){
        System.out.println(b);
    }
}

To test it, make sure you have a file (mine was "books.csv") in your root directory of your Java project. Mine looked like:

bob,jones,1993
bob,dillon,1994
bad,format
good,format,1995
another,good,1992
bad,format2
good,good,1997

And with the above main method, getList function, and file, my code generator the following output (note: the error messages were in red for the Std.err stream, SO doesn't show colors):

Some error message here
Some error message here
[title=bob, author=jones, years=1993]
[title=bob, author=dillon, years=1994]
[title=good, author=format, years=1995]
[title=another, author=good, years=1992]
[title=good, author=good, years=1997]

Feel free to ask questions if you are confused on any part of it. The output shown is from a toString() method I wrote on the Book class that I used for testing the code in my answer.

Mike Elofson
  • 2,017
  • 1
  • 10
  • 16
  • This really is a great answer, but there are a few conflicts with the set parameters of the assignment. See, the file itself is defined as a String in the method parameters, likely inputed there from a Scanner or something defined in the main method. From what I can tell, the BufferedReader class has no way of just reading a simple String. I can see that you're using a FileReader, but will it read from the String file itself? – Grayson Erickson Jan 20 '15 at 20:37
  • Another issue is in the bookDetails array. See, the parameter for years is an int, meaning that the constructor for Book is Book(String title, String author, int years). However, bookDetails, as it is defined as an array of Strings, is trying to put the years parameter in as a String, which means it can't instantiate. And as far as I can tell, there's no way to make a String an int in the way that I need it. – Grayson Erickson Jan 20 '15 at 20:39
  • By the file is a string, do you mean that it is a path to the file? Or the entire contents of the file? `BufferedReader` is a simple IO reader, it should be able to read a string as far as I am aware. As for the `int` issue, you can use the `Integer.parseInt(String s)` function. `int` is a primitive type, but `Java` has wrappers (`Integer` for example) around the primitive types to add functionality. So, for the constructor for the book, you can use `Integer.parseInt(bookDetails[2])`, or whatever index the year is at. – Mike Elofson Jan 20 '15 at 20:48
  • I mean the entire contents of the file. At least, that's how I'm interpreting the assignment. – Grayson Erickson Jan 20 '15 at 20:59
  • In your question, you state that the question asks: `The method getList should readin the data from the csv file book.csv`. This implies that before the `getList` function, you have no data from the csv file. With that in mind, I believe that you are given a name/path to a csv file and are expected to read it that way. I have updated my answer with more code snippets you can use for testing. – Mike Elofson Jan 20 '15 at 21:01
  • Well, it's taken quite a bit of work, but it seems that we've managed to get it working. Thanks so much for your help. There's still plenty of work to be done on the program (mainly in terms of sorting it), but as far as the getList method, I think I can safely consider this question solved. – Grayson Erickson Jan 20 '15 at 23:14
0

You can use a do while loop and read it till the end of file. Each new line will represent a Book Object detail. In a csv all details are comma separated, So you can read the string and each comma will act as a delimiter between attributes of Book.