I have the following code
public static int[] readCSV() {
ArrayList<Integer> entries = new ArrayList<>();
try {
File file = new File("someDataFile.csv");
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
String line = "";
String[] row;
while((line = br.readLine()) != null) {
row = line.split(",");
for(String value : row) {
int entry = Integer.parseInt(value);
entries.add(entry);
}
}
br.close();
} catch(IOException ioe) {
ioe.printStackTrace();
}
int[] IDs = entries.toArray();
return IDs;
}
Every entry of the csv is an integer stored as a string. I get the following error: "Type mismatch: cannot convert from Object[] to int[]". As far as I understand, "entries" is not an Object[] here, it's an ArrayList<Integer>.
I was using an example given on geeksforgeeks. That didn't work and I'm not sure why.
I also checked the previous answers to the same question, and the top answer works for me. That said, I still don't have an int[], I only have Integer[]. Then I have to do this to convert from Integer[] to int[]. My question is why do I have to do all that instead of int[] IDs = entries.toArray();?
If I do
int[] IDs = new int[entries.size()];
for (int i=0; i<entries.size(); i++) {
IDs[i] = entries.get(i);
}
it works fine. Why is that different from int[] IDs = entries.toArray()?
Is there a better way to get the contents of the csv file in an int[]?
First, to answer your question, because a collection (like ArrayList) can only contain object instances. That means you must use the Integer wrapper type instead of the int primitive type. However, in Java 8+, there are simple ways to perform that conversion. I would also strongly recommend a try-with-Resources over manually closing the BufferedReader. I also simplified the code a little. Like,
public static int[] readCSV() {
List<Integer> entries = new ArrayList<>();
File file = new File("someDataFile.csv");
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
while ((line = br.readLine()) != null) {
String[] row = line.split("\\s*,\\s*"); // Consume white space
for (String value : row) {
entries.add(Integer.parseInt(value));
}
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
return entries.stream().mapToInt(Integer::intValue).toArray();
}
List#toArray always returns an Object[]. The closest you can get is entries.toArray(new Integer[0]) to get an Integer[].
To get an int[] you can use the Streams API or loop over the List and copy it over to an array.
Integer[] arr = list.toArray(new Integer[0]);
int[] arr2 = list.stream().mapToInt(i -> i).toArray();
Related
I am doing a simple Data Frame that can read and write CSV while being able to edit the data. I have encountered a problem when I am trying to concatenate a new column to my data frame.
This is the sample input of the file:
Name,Age,Salary
Lim,20,2000
Tan,20,3000
Mah,19,2500
Roger,10,4000
And this is my code to concatenate the columns :
String filePath = "\...\Book1.csv";
String line;
List<List<String>> data = new ArrayList();
try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
while ((line = br.readLine()) != null) {
List<String> column = Arrays.asList(line.split(","));
data.add(column);
}
} catch (Exception e) {
System.out.println(e);
}
System.out.println(data.toString());
String [] newColumn = {"Colour", "Green", "Blue", "Black","Yellow"};
for(int i = 0 ; i<data.size(); i++){
List<String> temp = data.get(i);
temp.add(newColumn[i]);
}
System.out.println(data.toString());
The output will be like this :
[[Name, Age, Salary], [Lim, 20, 2000], [Tan, 20, 3000], [Mah, 19, 2500], [Roger, 10, 4000]]
Exception in thread "main" java.lang.UnsupportedOperationException
at java.base/java.util.AbstractList.add(AbstractList.java:153)
at java.base/java.util.AbstractList.add(AbstractList.java:111)
at Testing.main(Testing.java:31)
System.out.println(data.toString());
How am I going to change the code to be able to read the newColumn and store it into data?
From the Javadoc for Arrays.asList:
Returns a fixed-size list backed by the specified array
You need to create a new ArrayList if you wish to add to it.
List<String> column = new ArrayList(Arrays.asList(line.split(",")));
I wrote a code to sort a multidimensional ArrayList ArrayList<String[]> by the 1st element of each String[], the 2dArray looks like this:
{
["Mark", "mark#mail.com"],
["Angela", "zzAngela#gmail.com"],
["Harry", "abc_harry#hotmail.com"],
["Donald","donny#aol.com"]
}
But when I run the code the array doesn't get sorted, can someone explain what is wrong with my code? Thank you already!
ArrayList<String[]> sorter = new ArrayList<String[]>();
String file_name = "db_email.csv";
// READING FROM CSV FILE & STORING DATA INTO 2dARRAY
try{
BufferedReader reader = new BufferedReader(new FileReader (file_name));
String line = reader.readLine(); // read the rest
String[] row;
while(line != null){
String[] result = line.split(",");
sorter.add(new String[]{result[0], result[1]});
line = reader.readLine();
}
reader.close();
} catch (IOException e){
System.out.println(e);
}
// MY SORTING ALGORITHM
Collections.sort(sorter, new Comparator<String[]>() {
#Override
public int compare(String[] o1, String[] o2) {
return o1[0].compareTo(o2[0]);
}
});
// EXPECTED RESULT (sorting 2dArray by 1st column):
{
["Angela", "zzAngela#gmail.com"],
["Donald","donny#aol.com"],
["Harry", "abc_harry#hotmail.com"],
["Mark", "mark#mail.com"]
}
// ACTUAL RESULT (the array doesn't get sorted):
{
["Mark", "mark#mail.com"],
["Angela", "zzAngela#gmail.com"],
["Harry", "abc_harry#hotmail.com"],
["Donald","donny#aol.com"]
}
I finally resolved the issue, I was testing the sorting algorithm by adding a line like "aaaaa,myname#mail.com". I was unaware of the capitalization issue (probably bc it compares the numerical Unicode value), therefore the above line was always placed last. When I tested with a normal line like "Peter White,peter#me.com" it was working as expected.
Thank you all for your help & suggestions!
I'm currently working on a program that reads in a preset text file and then manipulates the data in various ways. I've got the data manipulation to work with some dummy data but I still need to get the text file read in correctly.
The test file looks like this for 120 lines:
Aberdeen,Scotland,57,9,N,2,9,W,5:00,p.m. Adelaide,Australia,34,55,S,138,36,E,2:30,a.m. Algiers,Algeria,36,50,N,3,0,E,6:00,p.m.(etc etc)
So each of these needs to be read into its own array, in order String[] CityName,String[] Country,int[] LatDeg,int[] LatMin,String[] NorthSouth,int[] LongDeg,int LongMin,String[] EastWest,int[] Time.String[] AMPM
So the problem is that while I'm reasonably comfortable with buffered readers, designing this particular function has proven difficult. In fact, I've been drawing a blank for the past few hours. It seems like it would need multiple loops and counters but I can't figure out the precisely how.
I am assuming that you have one city per line type of file structure. If it is not, it will require a bit of tweaking in the following solution:
I will do the following way if I am more comfortable with BufferReader as you say:
List<List<String>> addresses = new ArrayList<List<String>>();
try(BufferedReader br = new BufferedReader(new FileReader(file))) {
for(String line; (line = br.readLine()) != null; ) {
addresses.add(line.split(","));
}
}
Later, let's say you want to retrieve the country information of say 'Adelaid', you can try the following:
for (List<String> cityInfo : addresses) {
if("Adelaid".equals(cityInfo.get(0)) {
country = cityInfo.get(1);
}
}
Instead of creating different arrays (like String[] CityName,String[] Country, etc.,), try using a Domain Object.
Here, you can have a Domain object or Custom class Location with attributes
public class Location
{
private String cityName;
private String country;
private String latDeg;
etc
getters();
setters();
}`
Then you can write a file reader, each line item in the file will be a Location. So result will have
Location[] locations;
or
List locations;`
To carry out this task I should think the first thing you want to do is establish how many lines of data actually exist within the data file. You say it is 120 lines but what if it happens that it will be more or less? We would want to know exactly what it is so as to properly initialize all our different Arrays. We can use a simple method to accomplish this, let's call it the getFileLinesCount() method which will ulitmately return a Integer value that would be the number of text lines the data file holds:
private int getFileLinesCount(final String filePath) {
int lines = 0;
try{
File file =new File(filePath);
if(file.exists()){
FileReader fr = new FileReader(file);
try (LineNumberReader lnr = new LineNumberReader(fr)) {
while (lnr.readLine() != null){ lines++; }
}
}
else {
throw new IllegalArgumentException("GetFileLinesCount() Method Error!\n"
+ "The supplied file path does not exist!\n(" + filePath + ")");
}
}
catch(IOException e){ e.printStackTrace(); }
return lines;
}
Place this method somewhere within your main class. Now you need to Declare and initialize all your Arrays:
String filePath = "C:\\My Files\\MyDataFile.txt";
int lines = getFileLinesCount(filePath);
String[] CityName = new String[lines];
String[] Country = new String[lines];
int[] LatDeg = new int[lines];
int[] LatMin = new int[lines];
String[] NorthSouth = new String[lines];
int[] LongDeg = new int[lines];
int[] LongMin = new int[lines];
String[] EastWest = new String[lines];
int[] Time = new int[lines];
String[] AMPM = new String[lines];
Now to fill up all those Arrays:
public static void main(String args[]) {
loadUpArrays();
// Do whatever you want to do
// with all those Arrays.....
}
private void loadUpArrays() {
// Read in the data file.
try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
String sCurrentLine;
int x = 0;
// Read in one line at a time and Fill the Arrays...
while ((sCurrentLine = br.readLine()) != null) {
// Split each line read into an array upon itself.
String[] fileLine = sCurrentLine.split(",");
// Fill our required Arrays...
CityName[x] = fileLine[0];
Country[x] = fileLine[1];
LatDeg[x] = Integer.parseInt(fileLine[2]);
LatMin[x] = Integer.parseInt(fileLine[3]);
NorthSouth[x] = fileLine[4];
LongDeg[x] = Integer.parseInt(fileLine[5]);
LongMin[x] = Integer.parseInt(fileLine[6]);
EastWest[x] = fileLine[7];
Time[x] = Integer.parseInt(fileLine[8]);
AMPM[x] = fileLine[9];
x++;
}
br.close();
}
catch (IOException ex) { ex.printStackTrace(); }
}
Now, I haven't tested this, I just quickly punched it out but I think you can get the jest of it.
EDIT:
As #Mad Physicist has so graciously pointed out within his comment below, a List can be used to eliminate the need to count file lines therefore eliminating the need to read the data file twice. All the file lines can be placed into the List and the number of valid file lines can be determined by the size of the List. Filling of your desired arrays can now also be achieved by iterating through the List elements and processing the data accordingly. Everything can be achieved with a single method we'll call fillArrays(). Your Arrays declaration will be a little different however:
String[] CityName;
String[] Country;
int[] LatDeg;
int[] LatMin;
String[] NorthSouth;
int[] LongDeg;
int[] LongMin;
String[] EastWest;
String[] Time;
String[] AMPM;
public static void main(String args[]) {
fillArrays("C:\\My Files\\MyDataFile.txt");
// Whatever you want to do with all
// those Arrays...
}
private void fillArrays(final String filePath) {
List<String> fileLinesList = new ArrayList<>();
try{
File file = new File(filePath);
if(file.exists()){
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String strg;
while((strg = br.readLine()) != null){
// Make sure there is no blank line. If not
// then add line to List.
if (!strg.equals("")) { fileLinesList.add(strg); }
}
br.close();
}
}
else {
throw new IllegalArgumentException("GetFileLinesCount() Method Error!\n"
+ "The supplied file path does not exist!\n(" + filePath + ")");
}
// Initialize all the Arrays...
int lines = fileLinesList.size();
CityName = new String[lines];
Country = new String[lines];
LatDeg = new int[lines];
LatMin = new int[lines];
NorthSouth = new String[lines];
LongDeg = new int[lines];
LongMin = new int[lines];
EastWest = new String[lines];
Time = new String[lines];
AMPM = new String[lines];
// Fill all the Arrays...
for (int i = 0; i < fileLinesList.size(); i++) {
String[] lineArray = fileLinesList.get(i).split(",");
CityName[i] = lineArray[0];
Country[i] = lineArray[1];
LatDeg[i] = Integer.parseInt(lineArray[2]);
LatMin[i] = Integer.parseInt(lineArray[3]);
NorthSouth[i] = lineArray[4];
LongDeg[i] = Integer.parseInt(lineArray[5]);
LongMin[i] = Integer.parseInt(lineArray[6]);
EastWest[i] = lineArray[7];
Time[i] = lineArray[8];
AMPM[i] = lineArray[9];
}
}
catch(IOException e){ e.printStackTrace(); }
}
On another note...your Time Array can not be Integer since in data, what is considered the time contains a colon (:) which is a alpha character therefore (in case you haven't noticed) I have changed its declaration to String[]
I got this code here:
try{
FileReader file = new FileReader("/Users/Tda/desktop/ReadFiles/tentares.txt");
BufferedReader br = new BufferedReader(file);
String line = null;
while((line = br.readLine()) != null){
String[] values = line.split(",");
grp1 = new int[values.length];
for(int i=0; i<grp1.length; i++){
try {
grp1[i]= Integer.parseInt(values[i]);
}catch (NumberFormatException e) {
continue;
}
}
System.out.println(Arrays.toString(grp1));
}
System.out.println("");
br.close();
}catch(IOException e){
System.out.println(e);
}
This is what the file im reading contains.
grp1:80,82,91,100,76,65,85,88,97,55,69,88,75,97,81
grp2:72,89,86,85,99,47,79,88,100,76,83,94,84,82,93
Right now im storing the values into one int array.
But if i wanted to store each line of values into two arrays?
Thought about using Arrays.CopyOfRange somehow, and copy the values from the int array
into two new arrays.
This answer won't correspond to your question, but will give a hint to my comment under your question post.
Try this at the beginning of your while loop:
Use String.IndexOf() to find the first occurence of the char : into each line. This will be the beginning index for the second part.
Call String.Substring() from your new beginning index to line.length. This will give you the line without the characters and your first numbers aren't lost.
Before the while
List<int[]> groups = new ArrayList<>();
Before the end of the loop:
groups.add(grp1);
Afterwards:
for (int[] grp : groups) {
...
}
A List is useful for a growing "array".
groups.size() grp1.length
groups.get(3) grp1[3]
groups.set(3, x) grp1[3 = x
I have a multidimensional array built from Strings that is initially created with the size [50][50], this is too big and now the array is full of null values, I am currently trying to remove these said null values, I have managed to resize the array to [requiredSize][50] but cannot shrink it any further, could anyone help me with this? I have scoured the internet for such an answer but cannot find it.
Here is my complete code too (I realise there may be some very unclean parts in my code, I am yet to clean anything up)
import java.io.*;
import java.util.*;
public class FooBar
{
public static String[][] loadCSV()
{
FileInputStream inStream;
InputStreamReader inFile;
BufferedReader br;
String line;
int lineNum, tokNum, ii, jj;
String [][] CSV, TempArray, TempArray2;
lineNum = tokNum = ii = jj = 0;
TempArray = new String[50][50];
try
{
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Please enter the file path of the CSV");
String fileName = in.readLine();
inStream = new FileInputStream(fileName);
inFile = new InputStreamReader(inStream);
br = new BufferedReader(inFile);
StringTokenizer tok,tok2;
lineNum = 0;
line = br.readLine();
tokNum = 0;
tok = new StringTokenizer(line, ",");
while( tok.hasMoreTokens())
{
TempArray[tokNum][0] = tok.nextToken();
tokNum++;
}
tokNum = 0;
lineNum++;
while( line != null)
{
line = br.readLine();
if (line != null)
{
tokNum = 0;
tok2 = new StringTokenizer(line, ",");
while(tok2.hasMoreTokens())
{
TempArray[tokNum][lineNum] = tok2.nextToken();
tokNum++;
}
}
lineNum++;
}
}
catch(IOException e)
{
System.out.println("Error file may not be accessible, check the path and try again");
}
CSV = new String[tokNum][50];
for (ii=0; ii<tokNum-1 ;ii++)
{
System.arraycopy(TempArray[ii],0,CSV[ii],0,TempArray[ii].length);
}
return CSV;
}
public static void main (String args[])
{
String [][] CSV;
CSV = loadCSV();
System.out.println(Arrays.deepToString(CSV));
}
}
The CSV file looks as follows
Height,Weight,Age,TER,Salary
163.9,46.8,37,72.6,53010.68
191.3,91.4,32,92.2,66068.51
166.5,51.1,27,77.6,42724.34
156.3,55.7,21,81.1,50531.91
It can take any size obviously but this is just a sample file.
I just need to resize the array so that it will not contain any null values.
I also understand a list would be a better option here but it is not possible due to outside constraints. It can only be an multi dimensional array.
I think you need 3 changes to your program
After your while loop lineNum will be 1 more than the number of lines in the file so instead of declaring CSV to String[tokNum][50] declare it as CSV = new String[tokNum][lineNum-1];
tokNum will be the number of fields in a row so your for loop condition should be ii<tokNum rather than ii<tokNum-1
The last parameter for your arraycopy should be lineNum-1
i.e. the modified code to build your CSV array is:
CSV = new String[tokNum][lineNum-1];
for (ii=0; ii<tokNum ;ii++)
{
System.arraycopy(TempArray[ii],0,CSV[ii],0,lineNum-1);
}
and the output will then be:
[[Height, 163.9, 191.3, 166.5, 156.3], [Weight, 46.8, 91.4, 51.1, 55.7],
[Age, 37, 32, 27, 21], [TER, 72.6, 92.2, 77.6, 81.1],
[Salary, 53010.68, 66068.51, 42724.34, 50531.91]]
Notice that you don't really need to handle the first line of the file separately from the others but that is something you can cover as part of your cleanup.
10 to 1 this is a homework assignment. However, it looks like you've put somethought into it.
Don't make the TempArray variable. Make a "List of List of Strings". Something like:
List<List<String>> rows = new ArrayList<ArrayList<String>>();
while(file.hasMoreRows()) { //not valid syntax...but you get the jist
String rowIText = file.nextRow(); //not valid syntax...but you get the jist
List<String> rowI = new ArrayList<String>();
//parse rowIText to build rowI --> this is your homework
rows.add(rowI);
}
//now build String[][] using fully constructed rows variable
Here's an observation and a suggestion.
Observation: Working with (multidimensional) arrays is difficult in Java.
Suggestion: Don't use arrays to represent complex data types in Java.
Create classes for your data. Create a List of people:
class Person {
String height; //should eventually be changed to a double probably
String weight; // "
//...
public Person( String height, String weight /*, ... */ ) {
this.height = height;
this.weight = weight;
//...
}
}
List<Person> people = new ArrayList<Person>();
String line;
while ( (line = reader.nextLine()) != null ) {
String[] records = line.split(",");
people.add(new Person (records[0], records[1] /*, ... */));
}