user47
user47

Reputation: 131

How to convert a 2d array into a 2d ArrayList in java?

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

Answers (1)

Ivo Mori
Ivo Mori

Reputation: 2338

Going back to what was pointed out in the comments

  1. Don't use a 2D array (or a 2D list) because you'd be using something similar to parallel arrays or parallel lists as your data structure. See Jon Skeet's Anti-Pattern: Parallel Collections blog for details.
  2. Also by trying to solve your problem with a 2D array/list your code gets much more complicated than actually necessary (and for no good reason).

So how could an approach look like as pointed out in the comments?

Following code

  • reads a test file line by line,
  • processes each line into a User instance,
  • and collects them all into an 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

Related Questions