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.
Going back to what was pointed out in the comments
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.
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.
I am trying to find the longest possible path based on how many connections a variable number has, without repeating connections. The way I thought of doing this was creating a list that holds all points that have already been gone through, but when a path ends, and I need to check a new path, all of those old connections remain in the list. How can I restart my list from the initial point?
Putting it in the recursive function itself would just clear the list each time. Is there a better option than using a list?
Relevant code:
package testapp;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.io.IOException;
import java.util.List;
class TestApp {
// Store list of objects we have already matched with
static List<NumberObject> holdingList = new ArrayList<NumberObject>();
//Test objects
static int[] array1 = {2,2};
static int[] array2 = {3,1};
static int[] array3 = {2,1};
static int[] array4 = {1,1};
static NumberObject eight = new NumberObject(array1, 8);
static NumberObject two = new NumberObject(array2, 2);
static NumberObject three = new NumberObject(array3, 3);
static NumberObject four = new NumberObject(array4, 4);
// Test objects ^^
public static int longestSequence(int[][] grid) {
// TODO: implement this function
// Code exists here not relevant to the problem
//Setting up a new numberList array for testing
NumberObject[] newNumberList = {eight, two, three, four};
NumberObject[] connections1 = {two, four};
NumberObject[] connections2 = {two, three};
//Adding connections
eight.connections = connections1;
four.connections = connections2;
for (NumberObject s: newNumberList){
recursive(s);
}
return 0;
}
public static void recursive(NumberObject object){
for (NumberObject x: holdingList){
System.out.println(x);
}
if (!holdingList.contains(object)){
holdingList.add(object);
if (object.hasConnections()){
NumberObject[] newobject = object.getConnections();
for(NumberObject y: newobject){
recursive(y);
}
}
else {
System.out.println(holdingList.size());
return;
}
}
else {
System.out.println(holdingList.size());
return;
}
}
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
int numRows = 0;
int numCols = 0;
String[] firstLine = reader.readLine().split("\\s+");
numRows = Integer.parseInt(firstLine[0]);
numCols = Integer.parseInt(firstLine[1]);
int[][] grid = new int[numRows][numCols];
for (int row = 0; row < numRows; row++) {
String[] inputRow = reader.readLine().split("\\s+");
for (int col = 0; col < numCols; col++) {
grid[row][col] = Integer.parseInt(inputRow[col]);
}
}
int length = longestSequence(grid);
System.out.println(length);
}
}
class NumberObject {
int[] id;
int value;
NumberObject[] connections;
//Constructor
public NumberObject(int[] id, int value){
this.id = id;
this.value = value;
}
//print statement
public String toString(){
return ("NumberOject: Id = " + id + "\nValue = " + value);
}
//Check if it has connections
public boolean hasConnections(){
if (connections == null){
return false;
}
else if (connections.length != 0){
return true;
}
else
return false;
}
//Return the connections it has
public NumberObject[] getConnections(){
return connections;
}
}
Ideally, the image displays what I want to happen.
Instead, all the old branching connections remain on holdingList.
it should be noted paths can branch off to more than two other objects.
Instead of storing the list in a field, you could just pass an instance of a copy of your list to the function as an argument. So the signature of your function recursive would look like:
public static void recursive(NumberObject object, List<NumberObject> visited)
To hide this implementation detail, I recommend writing two functions, whereby the second function just passes an empty list to the other one.
However, I'd choose a different approach since yours acquires as many new lists as entries are in your tree. In the following implementation, you only have one list per "tree end". Moreover, just like in the previous suggestion, this keeps your class stateless.
static List<NumberObject> findLongestPath(NumberObject currentNode) {
if (currentNode.getConnectedNodes().isEmpty()) {
List<NumberObject> result = new ArrayList<>();
result.add(currentNode);
return result;
}
List<NumberObject> longestPath = currentNode.getConnectedNodes().stream()
.map(PathFinder::findLongestPath)
.max(Comparator.comparing(List::size))
.get();
longestPath.add(currentNode);
return longestPath;
}
I would like some guidance on this particular code that I am testing but currently it is not printing out anything and on top of that I feel as if it isn't reading the text file at all. It seems to finish right away with no errors and I only get prompted that "build is successful."
The assignment is to read from a data text file that list 20 lines of student information, each line is comprised of first name, last name, and their grade all seperated by spaces. I am put to it into an array and output their information, but for now I am testing to see if it will output the first name before I proceed.
public class studentClass {
private String studentFName, studentLName;
private int testScore;
private char grade;
//constructor
public studentClass(String stuFName, String stuLName, int stuTestScore){
studentFName = stuFName;
studentLName = stuLName;
testScore = stuTestScore;
}
public String getStudentFName(){
return studentFName;
}
public String getStudentLName(){
return studentLName;
}
public int getTestScore(){
return testScore;
}
public char getGrade(){
return grade;
}
public void setStudentFName(String f){
studentFName = f;
}
public void setStudentLName(String l){
studentLName = l;
}
public void setTestScore(int t){
if (t>=0 && t<=100){
testScore = t;
}
}
public void setGrade(char g){
grade = g;
}
}
public static void main(String[] args) throws IOException {
int numberOfLines = 20;
studentClass[] studentObject = new studentClass[numberOfLines];
for(int i = 0; i>studentObject.length; i++){
System.out.print(studentObject[i].getStudentFName());
}
}
public static studentClass[] readStudentData(studentClass[] studentObject)throws IOException{
//create FileReader and BufferedReader to read and store data
FileReader fr = new FileReader("/Volumes/PERS/Data.txt");
BufferedReader br = new BufferedReader (fr);
String lines = null;
int i = 0;
//create array to store data for firstname, lastname, and score
while ((lines = br.readLine()) != null){
String stuArray[] = lines.split(" ");
String stuFName = stuArray[0];
String stuLName = stuArray[1];
int score = Integer.parseInt(stuArray[2]);
studentObject[i] = new studentClass (stuFName, stuLName, score);
i++;
}
return studentObject;
}
You need to actually call the method to read in the data. Try the following (note I didn't handle the Exception. I leave that as an exercise to you)
public static void main(String[] args) throws IOException {
int numberOfLines = 20;
studentClass[] studentObject = new studentClass[numberOfLines];
readStudentData(studentObject);
//NOTE I CHANGED THE '>' TO '<'
for(int i = 0; i < studentObject.length; i++){
System.out.print(studentObject[i].getStudentFName());
}
}
//Note that I changed the return type to void
public static void readStudentData(studentClass[] studentObject)throws IOException{
//Your code here
You'll see I changed your readStudentData to return void since you're passing the array into the method you don't need to return it. You'll need to remove the return at the end of it.
You could also leave it as a method returning a studentClass[] and have no parameters. Instead, create the studentClass array inside readStudentData. I would recommend that approach because it removes the need to create and pass the array, which complicates your main method.
I'm a beginner when it comes to Java and I'm trying to pull these values vertically and store them in a data type with their reference. So "A" would have 1,8,7,6 mapped to it and the dates in front would be excluded as well. The csv file is below.
10/1/14, A,B,C,D,E,F,G,H
10/2/14, 1,2,3,4,5,6,7,8
10/3/14, 8,1,2,3,4,5,6,7
10/4/14, 7,8,1,2,3,4,5,6
10/5/14, 6,7,8,1,2,3,4,5
Here is my code. So far I've been able to grab the rows individually, but I'm I don't know how to add them to a data structure. This would return >> C3218
class Main {
public static void main(String[] args) {
Read r = new Read();
r.openFile();
r.readFile();
r.closeFile();
}
}
import java.io.*;
import java.util.*;
public class Read {
private Scanner x;
public void openFile() {
try {
x = new Scanner(new File("test.csv"));
}
catch(Exception e){
System.out.println("could not find file");
}
}
public void readFile() {
while(x.hasNext()){
String a = x.next();
String[] values = a.split(",");
System.out.printf(values[3]); // gets line
}
}
public void closeFile() {
x.close();
}
}
Java is an Object Oriented programming language. I'm going to assume that what you call "data structures" are Objects in Java parlance. For example (and these are just examples, not something you specifically could use for your situation), if I want to represent a person, I might have something like this
public interface Person{
String getName();
Date getBirthDate();
}
public class GenericPerson implements Person{
private final String name;
private final Date bdate;
public GenericPerson(String fullName, Date birthdate){
name = fullName;
bdate = birthdate;
}
#Override
public String getName() {
return name;
}
#Override
public Date getBirthDate() {
return bdate;
}
}
Pretty sparse, but I'm just trying to show some basic concepts.
You asked
I don't know how to add them to a data structure.
In my example, you would instantiate a GenericPerson
Person p = new GenericPerson(name,date);
Of course, you'll need the name and date variables. That's where the parsing the file comes in. So if I had a file of the form
George Costanza,5/4/1956
Cosmo Kramer,12/12/1960
Jerry Seinfeld,1/2/1959
Then in my code to parse the file I might have
String line = scanner.next();
String[] values = line.split(",");
Person p = new GenericPerson(values[0],getDateFormatter().parse(values[1]));
So you create your Object type, defining what fields you want it to have. And then populate them via a constructor or setter methods. An example of setter methods would be if I modified the GenericPerson like this
public class GenericPerson implements Person{
private String name;
private Date bdate;
public void setName(String n){
name = n;
}
public void setBirthDate(Date d){
bdate = d;
}
#Override
public String getName() {
return name;
}
#Override
public Date getBirthDate() {
return bdate;
}
}
Now I would need to call those to set the values in the Object.
For your case, you'll need to define some Object type that the data is meant to define. The type will have fields like the GenericPerson and you need to have setter methods or a constructor that takes arguments corresponding to the fields.
I highly recommend following the online tutorial for java beginners.
It took me 30 minutes just to get your code to compile and run correctly.
I used a List of a Column class that I created. The Column class contains the name of the column and the values in that CSV column.
The test.csv file is in the same directory as the Java class.
Here's the results.
A: 1, 8, 7, 6
B: 2, 1, 8, 7
C: 3, 2, 1, 8
D: 4, 3, 2, 1
E: 5, 4, 3, 2
F: 6, 5, 4, 3
G: 7, 6, 5, 4
H: 8, 7, 6, 5
And here's the code.
package com.ggl.testing;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class CSVColumns implements Runnable {
public static void main(String[] args) {
new CSVColumns().run();
}
#Override
public void run() {
Scanner scanner = openFile();
if (scanner != null) {
readFile(scanner);
closeFile(scanner);
}
}
private Scanner openFile() {
String fileString = "test.csv";
return new Scanner(getClass().getResourceAsStream(fileString));
}
private void readFile(Scanner scanner) {
List<Column> columnList = new ArrayList<>();
String a = scanner.nextLine();
a = a.replace(" ", "");
String[] values = a.split(",");
for (int i = 1; i < values.length; i++) {
Column column = new Column(values[i]);
columnList.add(column);
}
while (scanner.hasNext()) {
a = scanner.nextLine();
a = a.replace(" ", "");
values = a.split(",");
for (int i = 0; i < columnList.size(); i++) {
Column column = columnList.get(i);
column.addValue(Integer.valueOf(values[i + 1]));
}
}
for (int i = 0; i < columnList.size(); i++) {
System.out.println(columnList.get(i));
}
}
private void closeFile(Scanner scanner) {
scanner.close();
}
public class Column {
private List<Integer> values;
private final String name;
public Column(String name) {
this.name = name;
this.values = new ArrayList<>();
}
public List<Integer> getValues() {
return values;
}
public void addValue(int value) {
this.values.add(Integer.valueOf(value));
}
public String getName() {
return name;
}
#Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(name);
builder.append(": ");
for (int i = 0; i < values.size(); i++) {
int value = values.get(i);
builder.append(value);
if (i < (values.size() - 1)) {
builder.append(", ");
}
}
return builder.toString();
}
}
}
Using LinkedHashMap to store header(as Keys). LinkedHashMap preserves the insertion-order:
public void readFile() {
Map<String, String> map = new LinkedHashMap<String, String>();
boolean setInitValues = true, setKeys = true;
String[] keys = null;
while (x.hasNext()) {
String a = x.nextLine();
String[] values = a.split(",");
if (setKeys) { // set keys
keys = Arrays.copyOfRange(values, 1, values.length);
setKeys = false;
} else {
if (setInitValues) { // set initial values
for (int i = 1; i < values.length; i++)
map.put(keys[i - 1], values[i].trim());
setInitValues = false;
} else
// continue appending values
for (int i = 1; i < values.length; i++)
map.put(keys[i - 1],
map.get(keys[i - 1]).concat(values[i].trim()));
}
}
printMap(map); // print what you got
}
void printMap(Map<String, String> map) {
for (Map.Entry<String, String> entry : map.entrySet())
System.out.println("Key : " + entry.getKey() + " Value : "
+ entry.getValue());
}
Output :
Key : A Value : 1876
Key : B Value : 2187
Key : C Value : 3218
Key : D Value : 4321
Key : E Value : 5432
Key : F Value : 6543
Key : G Value : 7654
Key : H Value : 8765
i want to convert the instance of class which is in ArrayList to toString i have here my code
User class:
public class User {
// ...
public void setName(String name) {
this.fullname = name;
}
#Override
public String toString() {
return this.fullname;
}
public ArrayList<User> getTheLikers() {
ArrayList<User> user = new ArrayList<>();
user.add(this);
return user;
}
Post class:
public class Post {
public ArrayList<User> getLikers() {
User a = new User();
ArrayList<User> b = a.getTheLikers();
return b;
}
and here is the code where i should get the getLikers()
while(rs.next()) {
User a = new User();
Post b = new Post();
String name = rs.getString("people_who_like");
a.setName(name);
ArrayList c;
c = b.getLikers();
String liker = c.toString();
p.addElement(liker);
}
i have already convert it to toString as you can see.. but it shows that i have display my value but it is in null
To convert ArrayList into a String. That is specifically what the question says.
ArrayList c;
c = b.getLikers();
String liker = "";
for (String s : c){
liker += s + "\t";
}
When using Java 8 you can use String#join for this:
String liker = String.join(", ", c);
or the Stream API:
String liker = c.stream().collect(Collectors.joining(", "));
Pre Java 8 you have use e.g. Guava for this or write our own function
public static String listToString(final List<String> list) {
final StringBuilder result = new StringBuilder();
for (int i = 0; i < list.size() - 1; i++) {
result.append(list.get(i));
result.append(", ");
}
result.append(list.get(list.size() - 1));
return result.toString();
}
Even the list having the method List.toString() where u can get list into the String format.
how ever here the one thing that u can use your list to convert into the string.
Use the static variable for the list.
public class MainClass {
static ArrayList<String> arrayList = new ArrayList<String>();
public static void main(String args[]) {
arrayList.add("Krish");
arrayList.add("Krish1");
arrayList.add("Krish2");
arrayList.add("Krish3");
arrayList.add("Krish4");
System.out.println(arrayList.toString());
}
}
Similar u can use tostring method like this. if u using just arraylist then it will give out put in string format.
other way to do this.
public static String arrayliststring(ArrayList arrayList) {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < arrayList.size(); i++) {
buffer.append(arrayList.get(i).toString() + " ");
}
return buffer.toString();
}
hope this helps and for java 8 as ifloop said that is correct.