Reputation: 131
I have a Java program that reads elements from a file, stores them in a 2d array and then it manipulates them according by commiting several operations.
I have already implemented the program by using a 2d array and now I want to find a way to turn this array into a 2d ArrayList, so I can manipulate these elements individually, like i did with the 2d array.
The program reads from a file that looks like this:
Jason,56
Martha,89
James,23
...
Here is my code attempting to convert my 2d array into a 2d ArrayList:
Keep in mind that I want all the names to be stored in the 1st column of the array/ArrayList and the age in the second column:
public class Testr {
public static void main(String[] args) throws FileNotFoundException, IOException {
Scanner sc = new Scanner(new BufferedReader(new FileReader("C:\\Users\\test.csv")));
int num_rows = countLines("C:\\Users\\test.csv");
System.out.println("Num of rows : " + num_rows);
int num_cols = countColumns("C:\\Users\\test.csv");
System.out.println("Num of cols : " + num_cols);
String[][] Entries_arr = new String[num_rows][num_cols];
while(sc.hasNextLine())
{
for(int i = 0; i < Entries_arr.length; i++)
{
String[] line;
line = sc.nextLine().trim().split(";");
for(int j = 0; j < line.length; j++)
{
Entries_arr[i][j] = line[j];
}
}
}
List<List<String>> Entries = new ArrayList<List<String>>();
for(int i = 0; i < Entries_arr.length; i++)
{
List<String> recs = new ArrayList<String>();
for(int j = 0; j < Entries_arr[i].length; j++)
{
recs.add(String.valueOf(Entries_arr[i][j]));
}
Entries.add(recs);
}
System.out.println(Entries);
}
//------------------------------------------------------------------------------------------------------------------------
public static int countLines(String filename) throws IOException {
InputStream is = new BufferedInputStream(new FileInputStream(filename));
try {
byte[] c = new byte[1024];
int count = 0;
int readChars = 0;
boolean empty = true;
while ((readChars = is.read(c)) != -1) {
empty = false;
for (int i = 0; i < readChars; ++i) {
if (c[i] == '\n') {
++count;
}
}
}
return (count == 0 && !empty) ? 1 : count;
} finally {
is.close();
}
}
//------------------------------------------------------------------------------------------------------
public static int countColumns(String filename) {
File file = new File(filename);
Scanner scanner;
try {
scanner = new Scanner(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
return -1;
}
int number = 0;
if (scanner.hasNextLine()) {
number = scanner.nextLine().split(";").length;
}
scanner.close();
return number;
}
}
Any help is appreciated.
Upvotes: 0
Views: 217
Reputation: 2338
Going back to what was pointed out in the comments
So how could an approach look like as pointed out in the comments?
Following code
User
instance,ArrayList
.import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class FileToList {
public static void main(String[] args) {
try (Stream<String> lines = Files.lines(findCsvFile())) {
List<User> users = lines
.map(FileToList::process)
.flatMap(Optional::stream)
.collect(Collectors.toCollection(ArrayList::new));
System.out.println(users);
} catch (Exception e) {
System.out.println("Error when accessing the file\n");
e.printStackTrace();
}
}
static Path findCsvFile() throws Exception {
URL resource = FileToList.class.getResource(FileToList.class.getSimpleName() + ".class");
return Paths.get(resource.toURI()).resolveSibling("test.csv");
}
static Optional<User> process(String line) {
Optional<User> user = Optional.empty();
String[] values = line.split(",");
try {
String name = values[0];
int age = Integer.parseInt(values[1]);
User actualUser = new User(name, age);
user = Optional.of(actualUser);
} catch (Exception e) {
System.out.printf("Cannot process line: \"%s\" | Error: %s\n", line, e);
}
return user;
}
static class User {
private final String userFirstName;
private final int userAge;
User(String name, int age) {
this.userAge = age;
this.userFirstName = name;
}
public String getUserFirstName() {
return userFirstName;
}
public int getUserAge() {
return userAge;
}
@Override
public String toString() {
return String.format("%s(%d)", userFirstName, userAge);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return userAge == user.userAge &&
Objects.equals(userFirstName, user.userFirstName);
}
@Override
public int hashCode() {
return Objects.hash(userFirstName, userAge);
}
}
}
Running the above code against your example CVS file then outputs
[Jason(56), Martha(89), James(23)]
Note that Optional
is used in the process
method only to cover for the situation when a line from the CSV file cannot be processed into a new User
object. The .flatMap(Optional::stream)
then removes any potential optional (non-existing) user instances from the stream before collecting the actual users into an ArrayList
.
Upvotes: 1