This week's book giveaway is in the OCPJP forum.
We're giving away four copies of OCA/OCP Java SE 7 Programmer I & II Study Guide and have Kathy Sierra & Bert Bates on-line!
See this thread for details.
The moose likes Beginning Java and the fly likes Nested for loops to the point of confusion Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of OCA/OCP Java SE 7 Programmer I & II Study Guide this week in the OCPJP forum!
JavaRanch » Java Forums » Java » Beginning Java
Bookmark "Nested for loops to the point of confusion" Watch "Nested for loops to the point of confusion" New topic
Author

Nested for loops to the point of confusion

Dustin Schreader
Ranch Hand

Joined: May 25, 2009
Posts: 74
I get pretty confused when I have too many nested for loops. I've just about got this thing to work, it's reading in from a CSV file and I've got it to save one line of the CSV file to one portion of the array but it's only the last line from the CSV file. Any idea how to get the array to contain every row of the CSV file or maybe a more simple way to accomplish this?
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 8043
    
  22

Dustin Schreader wrote:Any idea how to get the array to contain every row of the CSV file or maybe a more simple way to accomplish this?

Well Lists are always useful, because you don't need to know how big they're going to be when you start.

A List<String> would be fine for keeping lines, but since you need to split the lines up too, you need to have a list of lists, viz:
List<List<String>>

and the most common class for using with arrays is ArrayList; so you end up with:
List<List<String>> csvFile = new ArrayList<List<String>>();

Another very useful method to know about is Arrays.asList(), which takes an array and returns it as a List.
So, putting it all together, your process loop might look something like:Once you have this, csvFile.get() will return you a row (as a List), so:
List<String> firstRow = csvFile.get(0);

and then you can use get() again to return an element, viz:
String thirdElement = firstRow.get(2);

You can also use for-each loops, just like you would with an array:
HIH

Winston


Isn't it funny how there's always time and money enough to do it WRONG?
Articles by Winston can be found here
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 8043
    
  22

Just in case you found the code I posted hard to follow, this line:
csvFile.add( Arrays.asList( dataRow.split(",") ) );

might be worthy of a bit of extra explanation, because it does quite a lot of stuff.

First remember that csvFile is a 'List of List of Strings'. It sounds quite a mouthful but in fact it's fairly straightforward:
1. The Strings are your String elements.
2. Each row in the file is a List of Strings (very similar to a String[]).
3. The file is a List of rows, ie, a List of List of Strings.

Going back to the line above and breaking it down:

You originally had a field called 'dataArray', OK:
String[] dataArray = dataRow.split(",");

now, as I explained before , Arrays.asList() will turn that into a List, so:
List<String> row = Arrays.asList(dataArray);

and finally, we have to add that "row" to the file:
csvFile.add(row);

All that first line does is do it all in one go, without having to create all those interim fields.

Sorry if it was unclear.

Winston
Dustin Schreader
Ranch Hand

Joined: May 25, 2009
Posts: 102
My goal is to read in from CSV file and then add a new item to it and then write all the info back to the CSV file. That way it looks like I just added something new to the CSV file. I suppose I should have mentioned that before, would there be an easier way of doing this?
Dustin Schreader
Ranch Hand

Joined: May 25, 2009
Posts: 102
I get an error for
It can't find the symbol method append(java.util.List<java.util.list<java.lang.String>>)
Dustin Schreader
Ranch Hand

Joined: May 25, 2009
Posts: 102
I managed to simplify my original code a lot but I'm getting an error for incompatible types and I'm not sure how to get around it.
Dustin Schreader
Ranch Hand

Joined: May 25, 2009
Posts: 102
I got it!
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 8043
    
  22

Dustin Schreader wrote:I got it!

Well done, but I'm afraid it's redundant.

If you look at the documentation for BufferedReader.readline(), you'll see that it already returns "the contents of the line, not including any line-termination characters".

Therefore:
dataArray = dataRow.split("\n");
will return exactly 1 element, so
rows[x] = dataArray[0];
is exactly the same thing as
rows[x] = dataRow;

Since, in your original code, you were splitting the line, I assumed that you needed to store all the CSV elements separately. Apologies for any confusion.

Winston
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 8043
    
  22

Dustin Schreader wrote:My goal is to read in from CSV file and then add a new item to it and then write all the info back to the CSV file. That way it looks like I just added something new to the CSV file. I suppose I should have mentioned that before, would there be an easier way of doing this?

Well if you need to add a new element to a line (unless it's only at the beginning or end) you're likely to have to split each line into elements, and that means either making it a String[] or a List<String>, as I suggested. The advantage of a List is that you don't have to worry about resizing; the class (eg, ArrayList) does it for you.

If you may also need to insert an entire row, then you're probably going to need some way of storing the file contents as a matrix.
Again, you have two choices:
String[][] (a two-dimensional String array) or a List<List<String>> (as I described above); and again, the advantage of using a List is that you don't need to worry about the resizing - although I admit, it does look a bit more verbose.

Winston
Joanne Neal
Rancher

Joined: Aug 05, 2005
Posts: 3720
    
  16
Winston Gutkowski wrote:Well if you need to add a new element to a line (unless it's only at the beginning or end) you're likely to have to split each line into elements, and that means either making it a String[] or a List<String>, as I suggested. The advantage of a List is that you don't have to worry about resizing; the class (eg, ArrayList) does it for you.

If you may also need to insert an entire row, then you're probably going to need some way of storing the file contents as a matrix.
Again, you have two choices:
String[][] (a two-dimensional String array) or a List<List<String>> (as I described above); and again, the advantage of using a List is that you don't need to worry about the resizing - although I admit, it does look a bit more verbose.

Winston

Actually you should create a Student class with a constructor that accepts the CSV line as a parameter. The constructor should then separate out the CSV elements and store them in instance variables. It would then need setter methods to modify the values. It can also override the toString method to output the values in a CSV format.

Note also that your method of splitting up the CSV line won't work if any of the elements contain commas. You are better off using a third party CSV library that will handle things like this.


Joanne
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 8043
    
  22

Joanne Neal wrote:Actually you should create a Student class with a constructor that accepts the CSV line as a parameter...

Absolutely. My answer was geared more to OP's original code.

Winston
Wendy Gibbons
Bartender

Joined: Oct 21, 2008
Posts: 1107

Joanne Neal wrote:
Note also that your method of splitting up the CSV line won't work if any of the elements contain commas. You are better off using a third party CSV library that will handle things like this.


people wouldn't allow commas in a csv file would they... *falls off chair laughing at her own joke*
Dustin Schreader
Ranch Hand

Joined: May 25, 2009
Posts: 102
Winston Gutkowski wrote:
Well done, but I'm afraid it's redundant.

If you look at the documentation for BufferedReader.readline(), you'll see that it already returns "the contents of the line, not including any line-termination characters".

Therefore:
dataArray = dataRow.split("\n");
will return exactly 1 element, so
rows[x] = dataArray[0];
is exactly the same thing as
rows[x] = dataRow;

Since, in your original code, you were splitting the line, I assumed that you needed to store all the CSV elements separately. Apologies for any confusion.

Winston

I tried

but I got an error

1 error found:
File: /Users/doodthatscool/Desktop/StudentsClass.java [line: 24]
Error: /Users/doodthatscool/Desktop/StudentsClass.java:24: incompatible types
found : java.lang.String[]
required: java.lang.String
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 39478
    
  28
That is because rows is an array of Strings, not an array of String arrays.
 
jQuery in Action, 2nd edition
 
subject: Nested for loops to the point of confusion