I am trying to read a txt file and trying to save it in an array.
following is the format of the txt file:
A B 5
A C 2
A D 4
.....
public class search {
public static void main(String[] args) throws ParseException {
try {
Scanner user_input = new Scanner(System.in); // for user input
System.out.println("Enter the file name: ");
String filename1 = user_input.next();
File file = new File(filename1);
search bd = new search();
Node[] nodes;
nodes = bd.getNodes(file);
bd.printNodes(nodes);
}
catch(Exception e) {
System.out.println("Error reading file " + e.getMessage());
}
}
public Node[] getNodes(File file) throws IOException {
FileReader bd = new FileReader(file);
BufferedReader bufferReader = new BufferedReader(bd);
String line;
ArrayList<Node>list = new ArrayList<Node>();
while ((line = bufferReader.readLine()) != null) {
String[] token = line.split(" "); // create string of tokens
list.add(new Node(token[0], token[1], Integer.parseInt(token[2])));
}
bufferReader.close();
return list.toArray(new Node[list.size()]); // converting list to array
}
public void printNodes(Node[] nodes) {
System.out.println("======================");
for(Node node : nodes) {
System.out.println(node);
}
System.out.println("======================");
}
Following is my Node class
class Node {
String leftchild;
String rightchild;
int cost;
public Node(){
}
public Node(String firstchild, String secondchild, int cost){
this.leftchild = firstchild;
this.rightchild = secondchild;
this.cost = cost;
}
public Node(String firstchild, String secondchild) {
this.leftchild = firstchild;
this.rightchild = secondchild;
}
public ArrayList<String> getChildren(){
ArrayList<String> childNodes = new ArrayList<String>();
if(this.leftchild != null)
{
childNodes.add(leftchild);
}
if(this.rightchild != null) {
childNodes.add(rightchild);
}
return childNodes;
}
public boolean removeChild(Node n){
return false;
}
#Override
public String toString() {
return leftchild +" "+ rightchild;
}
}
I have no compiling issues, but when I run my code, it is giving me error as
error reading file 1
Not sure why. I have tried to change my code in many ways but none of them worked. Could anyone please figure this out for me?
Thanks
If you get an ArrayIndexOutOfBoundsException: 1, it means that you have at least one line in your test input file that doesn't contain any spaces.
Indeed in your code you do String[] token = line.split(" ") which will extract all the tokens separated by a space and put them into an array of String, so if you get this error it means that the length of the array is 1 such that you cannot access to token[1] as it refers to the second element of your array that only contains one element.
So in your case you should test first if the length of the array has the right length as next:
String[] token = line.split(" "); // create string of tokens
if (token.length >= 3) {
list.add(new Node(token[0], token[1], Integer.parseInt(token[2])));
}
Related
I need help in adding Edge cost for my BFS algorithm. I don't have an idea how to add edge cost for the each vertex being added to the path. I will post code for your reference. Provide me some suggestions.
Graph.java
package algo;
import java.util.*;
public class Graph
{
private static Map<String, LinkedHashSet<HashMap<String, Double>>> map;
private ArrayList<String> nodes = new ArrayList<String>();
private static ArrayList<String> shortestPath = new ArrayList<String>();
public Graph()
{
}
public Graph(String[] nodes)
{
map = new HashMap<String,LinkedHashSet<HashMap<String, Double>>>();
for(int i=0;i<nodes.length;++i)
map.put(nodes[i], new LinkedHashSet<HashMap<String, Double>>());
}
public void addNeighbor(String node1,String node2, Double edgeCost)
{
LinkedHashSet<HashMap<String, Double>> adjacent = map.get(node1);
HashMap<String, Double> innerMap = new HashMap<String, Double>();
if(map.get(node1)==null)
{
adjacent = new LinkedHashSet<HashMap<String, Double>>();
map.put(node1, adjacent);
}
innerMap.put(node2, edgeCost);
adjacent.add(innerMap);
}
public boolean memberOf(String node) {
return nodes.contains(node);
}
public LinkedList<HashMap<String, Double>> getNeighbours(String node) {
LinkedHashSet<HashMap<String, Double>> adjacent = map.get(node);
if(adjacent==null) {
return new LinkedList<HashMap<String, Double>>();
}
return new LinkedList<HashMap<String, Double>>(adjacent);
}
protected void storeNodes(String source, String destination)
{
if (!source.equals(destination))
{
if (!nodes.contains(destination))
{
nodes.add(destination);
}
}
if (!nodes.contains(source)) {
nodes.add(source);
}
}
public void getKeyValuePairs()
{
Iterator<String> iterator = map.keySet().iterator();
while (iterator.hasNext())
{
String key = iterator.next().toString();
LinkedHashSet<HashMap<String, Double>> value = map.get(key);
System.out.println(key + " " + value);
}
}
}
Main.java
package algo;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException
{
File file = new File("city.txt");
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
String line = br.readLine();
String [] tokens = line.split("\\s+");
String [] nodes = new String[tokens.length];
for (int i = 0; i < nodes.length; ++i) {
nodes[i] = tokens[i];
}
Graph g = new Graph(nodes);
String var_1 = tokens[0];
String var_2 = tokens[1];
Double var_3 = Double.parseDouble(tokens[2]);
g.addNeighbor(var_1, var_2,var_3);
while((line = br.readLine())!=null)
{
tokens = line.split("\\s+");
nodes = new String[tokens.length];
for (int i = 0; i < nodes.length; ++i) {
nodes[i] = tokens[i];
}
//Graph g = new Graph(nodes);
var_1 = tokens[0];
var_2 = tokens[1];
var_3 = Double.parseDouble(tokens[2]);
g.addNeighbor(var_1, var_2,var_3);
g.storeNodes(var_1, var_2);
}
g.getKeyValuePairs();
br.close();
}
}
city.txt
city1 city2 5.5
city1 city3 6
city2 city1 16
city2 city3 26
city2 city4 15.5
city2 city5 7
city3 city4 9
city3 city5 5
city4 city1 3.6
city4 city2 4
city5 city2 7.9
city5 city3 5
this is my bfs part of my code which i have tested without adding any edgecost
public static ArrayList<String> breadthFirstSearch(Graph graph,
String source,
String destination)
{
shortestPath.clear();
// A list that stores the path.
ArrayList<String> path = new ArrayList<String>();
// If the source is the same as destination, I'm done.
if (source.equals(destination) && graph.memberOf(source))
{
path.add(source);
return path;
}
// A queue to store the visited nodes.
ArrayDeque<String> queue = new ArrayDeque<String>();
// A queue to store the visited nodes.
ArrayDeque<String> visited = new ArrayDeque<String>();
queue.offer(source);
while (!queue.isEmpty()) {
String vertex = queue.poll();
visited.offer(vertex);
ArrayList<String> neighboursList = (ArrayList<String>) graph.getNeighbours(vertex);
int index = 0;
int neighboursSize = neighboursList.size();
while (index != neighboursSize) {
String neighbour = neighboursList.get(index);
path.add(neighbour);
path.add(vertex);
if (neighbour.equals(destination)) {
return processPath(source, destination, path);
} else {
if (!visited.contains(neighbour)) {
queue.offer(neighbour);
}
}
index++;
}
}
return null;
}
public static ArrayList<String> processPath(String src,
String destination,
ArrayList<String> path)
{
// Finds out where the destination node directly comes from.
int index = path.indexOf(destination);
String source = path.get(index + 1);
// Adds the destination node to the shortestPath.
shortestPath.add(0, destination);
if (source.equals(src)) {
// The original source node is found.
shortestPath.add(0, src);
return shortestPath;
} else {
// We find where the source node of the destination node
// comes from.
// We then set the source node to be the destination node.
return processPath(src, source, path);
}
}
my question is how do I add the edgecost to code in bfs part and provide the path cost from source to destination when executed.
To return the path and the cost you will need to create a class to hold both values:
class CostedPath {
private final List<String> path = new ArrayList<>();
private double cost = 0.0;
public CostedPath(String start) {
path.add(start);
}
public CostedPath addNode(String node, Graph graph) {
this.cost += graph.getCost(path.get(0), node);
path.add(0, node);
return this;
}
}
Your search should then return a CostedPath from processPath.
private CostedPath processPath(String start, String end, List<String> path, Graph graph) {
{
String previous = path.get(path.indexOf(end) + 1);
if (previous.equals(start))
return new CostedPath(start);
else
return processPath(start, previous, path, graph).addNode(end, graph);
}
Your code would be a lot more readable if you split your classes up more.
class Vertex {
private final String name;
private final Set<Edge> edges;
}
class Edge {
private final Vertex end;
private final double cost;
}
class Graph {
private final Set<Vertex> vertices;
}
class Path {
private final Vertex start;
private final List<Edge> edges;
}
Once you've done that you'll find that it's a lot more obvious where to add logic that's related to a particular class and the data you need will be available when you need it. For example, it's now trivial to convert a Path to a total cost:
public double getCost() {
return edges.stream().mapToDouble(Edge::getCost).sum();
}
This is much cleaner code than having to pass the original graph around to find the cost of an edge.
I have a text file of cars with the following structure:
21
Vauxhall
Corsa
red
19
Vauxhall
Corsa
blue
18
Vauxhall
Corsa
White
I can load it into a HashMap but when I load it, it indexes every new line as a new element. How do I change this so after every 4 lines, it indexes?
Is there a way that I can also make it load into a elements such as:
id
Manufacturer
carMake
carColour
Hope this is what you wanted....
public static void main(String[] args) throws IOException {
Map<Integer, String> map = new HashMap<Integer, String>();
BufferedReader reader = new BufferedReader(new FileReader("/home/Desktop/cars.txt"));
String line = "";
int i = 0;
while (line != null) {
String data = "";
for (int k = 0; k < 4; k++) {
data = data + "," + reader.readLine();
if (k == 3)
map.put(i, data);
}
line = reader.readLine();
i++;
}
System.out.println(map);
}
You should create a new POJO class for the Car and then populate the data you read from the text file in that POJO.
Also, I don't see any use of a HashMap as you are just adding the incremented counter as key. You can use a HashSet instead.
Here is the code snippet
public class Car {
private int id;
private String manufacturer;
private String carMake;
private String carColour;
/* Getter Setters */
}
Main Class:
Set<Car> set= new HashSet<>();
BufferedReader reader = new BufferedReader(new FileReader("cars.txt"));
String line = "";
while (line != null) {
Car car = new Car();
line = reader.readLine();
car.setId(line != null ? reader.readLine() : 0);
line = reader.readLine();
car.setManufacturer(line != null ? reader.readLine() : null);
line = reader.readLine();
car.setCarMake(line != null ? reader.readLine() : null);
line = reader.readLine();
car.setCarColour(line != null ? reader.readLine() : null);
set.add(car);
}
What you wrote will read each line an treat it same, as strings, and as such, you place it in the map. Java is OOP, so use it, create an object, place 4 variables for each line from car string group and then have a HashMap of such objects. Like:
public class Car {
private int id;
private String something;
private String type;
private String collor;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getSomething() {
return something;
}
public void setSomething(String something) {
this.something = something;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getCollor() {
return collor;
}
public void setCollor(String collor) {
this.collor = collor;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Car car = (Car) o;
return id == car.id;
}
#Override
public int hashCode() {
return id;
}
#Override
public String toString() {
return "Car{" +
"id=" + id +
", something='" + something + '\'' +
", type='" + type + '\'' +
", collor='" + collor + '\'' +
'}';
}
}
Make sure you have toString, hashCode and equals method in such objects, they are very important!
If you dont want to create a Car object with those four elements you could do this using Map of Integer and List<String>.
Map<Integer, List<String>> map = new HashMap<Integer, List<String>>();
BufferedReader reader = new BufferedReader(new FileReader("cars.txt"));
String line="";
int i=0;
List<String> list = new ArrayList<String>();
while (line != null) {
line = reader.readLine();
if (line == null || line.trim().equals("")) continue;
list.add(line);
if (i % 4 == 0) {
map.put(list.get(0), list);
list = new ArrayList<String>();
}
i++;
}
Create a Car bean and give it a constructor to build the object reading the file lines.
Once create the Car will add itself into the map.
static class Car{
String id;
String Manufacturer;
String carMake;
String carColour;
public Car(BufferedReader reader, Map<Integer, Car> map) throws Exception{
id = readLine(reader);
Manufacturer = readLine(reader);
carMake = readLine(reader);
carColour = readLine(reader);
map.put(map.size(), this);
}
private String readLine(BufferedReader reader) throws Exception{
String s = reader.readLine();
if(s == null){
throw new Exception("No more line...");
}
return s;
}
}
public static void main(String[] args) {
try{
Map<Integer, Car> map = new HashMap<Integer, Car>();
BufferedReader reader = new BufferedReader(new FileReader("cars.txt"));
try{
while (true) {
new Car(reader, map);
}
}catch(Exception e){
// Will be thrown at the end ov the file
}
for(int j=0;j<map.size();j++){
System.out.println(map.get(j));
}
System.out.println(map);
}catch(Exception e){
e.printStackTrace();
}
}
First you should understood what you are actually doing.
This loop that you are using to read file, reads every single line and put in in map under index i (it doesn't care what it actually got).
while (line != null) {
line = reader.readLine();
map.put(i,line);
i++;
}
So for your purpose you need to discern what data you are excepting in that loop.
{
id = reader.readLine();
Manufacturer = reader.readLine();
carMake = reader.readLine();
carColour = reader.readLine();
reader.readLine(); //empty space between data
...
}
Of course it would be good to check if you are getting any data, like putting it in if statements.
Your next move should be deciding how you want to store that data. There are many ways to do so. For example you could also use another hashMap
Map<Integer, Map<String>> map = new HashMap<>();
...
{
...
Map<String, String> car = new HashMap<>();
car.put("id", id);
car.put("manufacturer", manufacturer);
car.put("model", carMake);
car.put("color", carColor);
map.put(i, car);
}
EDIT:
Almost forgot, since your file have space between each car data, there is a need to read that empty line and ignore it
I am trying to get this code running as fast as possible when traversing through my stack of my DFS currently the input files are like so:
0 2
2 1
1 4
4 5
5 6
10 8
8 9
9 6
7 6
3 4
0 1
3 9
0 4
Where my Maze class will tie the numbers together and create a graph for me. After the graph is created my DFS class runs through traversing giving one or all solutions to the .txt file submitted.I have recently altered my Maze class as for it to run more efficiently but am being thrown errors and the data is parsing through to my DFS to be outputted. My Maze class is as follows:
import java.io.*;
import java.util.*;
public class Maze {
private final Map<Integer, Set<Integer>> adjList = new HashMap<>();
/**
* The main constructor that takes a String for reading maze file.
*
* #param file
*/
public Maze(File file) throws FileNotFoundException {
try (Scanner scan = new Scanner(file)) {
while (scan.hasNextInt()) {
int node1 = scan.nextInt();
int node2 = scan.nextInt();
this.connect(node1, node2);
this.connect(node2, node1);
}
}
}
/**
* Makes a unidirectional connection from node1 to node2.
*/
private void connect(int node1, int node2) {
if (!this.adjList.containsKey(node1)) {
this.adjList.put(node1, new HashSet<Integer>());
}
this.adjList.get(node1).add(node2);
}
/**
* Returns a human-readable description of the adjacency lists.
*/
public String toString() {
StringBuilder s = new StringBuilder();
for (Map.Entry<Integer, Set<Integer>> adj : this.adjList.entrySet()) {
int from = adj.getKey();
Set<Integer> to = adj.getValue();
s.append(from).append(" connected to ").append(to).append('\n');
}
return s.toString();
}
/**
* Returns the set of nodes connected to a particular node.
*
* #param node - the node whose neighbors should be fetched
*/
public Iterable<Integer> getadjList(int node) {
return Collections.unmodifiableSet(adjList.get(node));
}
/**
* Demonstration of file reading.
*/
public static void main(String[] args) throws FileNotFoundException {
System.err.print("Enter File: ");
Scanner scanFile = new Scanner(System.in);
String file = scanFile.nextLine();
Maze m = new Maze(new File(file));
System.out.println(m);
}
}
And my DFS looks like so.
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.Stack;
public class DFS {
//starting node, the route to the next node, has node been visited
private int startNode;
private int[] route;
private boolean[] visited;
// 2 main arguments - Maze File & user input
public DFS(Maze maze, int inputInt) {
int startNode = 0;
int goalNode = 1;
route = new int[maze.node];
visited = new boolean[maze.node];
//Takes user's input and runs desired function
if(inputInt == 1){
findOne(maze, startNode, goalNode);
}
else if (inputInt == 2){
findAll(maze, startNode, goalNode);
}
else {
System.out.println("input invalid. No Solution Returned");
}
}
//Put path to goal in the stack
public Stack<Integer> route(int toGoalNode) {
if (!visited[toGoalNode]) {
return null;
}
Stack<Integer> pathStack = new Stack<Integer>();
for (int routeGoalNode = toGoalNode; routeGoalNode != startNode; routeGoalNode = route[routeGoalNode]) {
pathStack.push(routeGoalNode);
}
pathStack.push(startNode);
reverseStack(pathStack);
return pathStack;
}
//Reverse the stack
public void reverseStack(Stack<Integer> stackToBeReverse) {
if (stackToBeReverse.isEmpty()) {
return;
}
int bottom = popBottomStack(stackToBeReverse);
reverseStack(stackToBeReverse);
stackToBeReverse.push(bottom);
}
//Pop the bottom of the stack
private int popBottomStack(Stack<Integer> stackToBeReverse) {
int popTopStack = stackToBeReverse.pop();
if (stackToBeReverse.isEmpty()) {
return popTopStack;
} else {
int bottomStack = popBottomStack(stackToBeReverse);
stackToBeReverse.push(popTopStack);
return bottomStack;
}
}
//performs DFS and unsets visited to give the result of all paths
private void findAll(Maze maze, int node, int goal) {
visited[node] = true;
if(node == goal) {
printPath(goal);
} else {
for (int con : maze.getadjList(node)) {
if (!visited[con]) {
route[con] = node;
findAll(maze, con, goal);
}
}
}
visited[node] = false;
}
//performs DFS and maintains visited marker giving only one path
private void findOne(Maze maze, int node, int goal) {
visited[node] = true;
for (int con : maze.getadjList(node)) {
if (!visited[con]) {
route[con] = node;
findOne(maze, con, goal);
}
}
}
//Traverse the connections to the goal and print the path taken
public void printPath( int toGoal) {
int goalNode = 1;
if (visited[toGoal]) {
System.out.println("Completed Path: ");
for (int t : route(toGoal)) {
if (t == toGoal) {
System.out.print(t);
} else {
System.out.print(t + " -> ");
}
}
System.out.println();
}
}
public static void main(String[] args) throws FileNotFoundException {
Scanner scanFile = new Scanner(System.in);
int goalNode = 1;
System.out.print("Enter maze file: ");
String file = scanFile.nextLine();
Maze maze = new Maze(new File(file));
Scanner scanInt = new Scanner(System.in);
System.out.print("Enter desired feedback (1 = one soultion, 2 = all): ");
int inputInt = scanInt.nextInt();
// maze.toString();
System.out.println(maze);
DFS dfs = new DFS(maze, inputInt);
dfs.printPath(goalNode);
}
}
I've been looking over it for a while and can't figure out exactly why the data is parsing and being used. Ive altered a few things here and there but have been thrown even more errors. They specifically say
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
at DFS.findOne(DFS.java:90)
at DFS.<init>(DFS.java:22)
at DFS.main(DFS.java:127)
Referencing to the lines of code:
visited[node] = true;
findOne(maze, startNode, goalNode);
DFS dfs = new DFS(maze, inputInt);
Now essentially im lead to believe that there is no argument being passed, if someone could pin point the problem and lend a hand in helping me out it would be greatly appreciated. Thanks again
EDIT:: Old version of Maze class
import java.io.*;
import java.util.*;
public class Maze {
static Set<Integer> Nodes = new HashSet<Integer>();
List<Integer>[] conList;
int node; //declaring value for my nodes.
int con; // declaring a connection
//Constructor takes an int parameter to read through the list of corresponding nodes
Maze(int node) {
this.node = node;
this.con = 0;
conList = (List<Integer>[]) new List[node];
for (int index = 0; index < node; index++) {
conList[index] = new LinkedList<Integer>();
}
}
//Constructor that takes a String of the maze file
public Maze(String mazeFile) {
this(nodeSize(mazeFile));
Scanner scan;
try {
//Creates a scanner for reading the file and loops through linking the nodes to their connections.
scan = new Scanner(new File(mazeFile));
while (scan.hasNextInt()) {
int firstNode = scan.nextInt();
int secondNode = scan.nextInt();
addCon(firstNode, secondNode);
}
} catch (FileNotFoundException ex) {
System.out.println("File Not Found.");
}
}
/*Takes String parameter which is the name of the maze file.
* Method designed to return the the size of the set of nodes
*/
public static int nodeSize(String mazeFile) {
Scanner scanNodeSize;
try {
scanNodeSize = new Scanner(new File(mazeFile));
//while scan has more int's left repeat.
while (scanNodeSize.hasNextInt()) {
int firstNode = scanNodeSize.nextInt();
int secondNode = scanNodeSize.nextInt();
Nodes.add(firstNode);
Nodes.add(secondNode);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return Nodes.size();
}
//Method designed to connect the first and second nodes
private void addCon(int firstNode, int secondNode) {
con++;
conList[firstNode].add(secondNode);
conList[secondNode].add(firstNode);
}
//outputs the nodes and their connection's (#remove later?)
public void print() {
for (int n = 0; n < node; n++) {
System.out.print(n + " connected to ");
for (int w : conList[n]) {
System.out.print(w + " ");
}
System.out.println();
}
}
//method returns a list, enabling nodes to be easily accessible.
public Iterable<Integer> getconList(int nodes) {
return conList[nodes];
}
}
You are getting an index out of bounds exception at 0. This should lead you to believe that the array has not properly been initialized. You initialize the visited[] array with maze.node however nowhere in your code do we see where this node variable is located. You need to give a proper value to maze.node if you want this to even be runnable.
*EDIT - My above answer is no longer applicable now that we have your previous Maze class which explains why the code will not run.
There are so many things wrong with the code in its current state so I will try and give you some direction here:
Your new way of creating a Maze is to read from the file and connect the 2 points and store them in an Map. The issue with this is that you cannot just get the next element since you have to have the key to get the element. To fix this you should use a different data structure.
public DFS(Maze maze, int inputInt) {
int startNode = 0;
int goalNode = 1;
route = new int[maze.node]; //!!! maze.node isn't a thing anymore
visited = new boolean[maze.node]; //!!! maze.node isn't a thing anymore
You can see that you are trying to access maze.node which use to be a variable of Maze. It no longer is. You need to find a new way of getting a node from Maze. To do this you need to grab the node from your data structure in a different way:
public DFS(Maze maze, int inputInt) {
int startNode = 0;
int goalNode = 1;
route = new int[maze.adjList.getNode()];
visited = new boolean[maze.adjList.getNode()];
You have a lot of options for a different data structure for you adjacency list but something such as this:
http://theoryofprogramming.com/adjacency-list-in-java/
will give you a decent starting point.
I'm having trouble understanding how to parse text documents with unknown amounts of 'students'. All my solutions are coming up strange and I'm having trouble with the Scanner. Breaking down the input, the first integer represents how many classes there are, the first string is the class name, the following are students with respective dates and variables that need to be stored along with the student, with an unknown amount of students. I want to store each student along with the class they are in.
My code is extremely messy and confusing so far:
String filename = "input.txt";
File file = new File(filename);
Scanner sc = new Scanner(file);
Student[] studArr = new Student[100];
int studCounter = 0;
boolean breaker = false;
boolean firstRun = true;
int numClasses = sc.nextInt();
System.out.println(numClasses);
while(sc.hasNextLine()){
String className = sc.nextLine();
System.out.println("Name: " + className);
String test = null;
breaker = false;
sc.nextLine();
// Breaks the while loop when a new class is found
while (breaker == false){
Student temp = null;
// Boolean to tell when the first run of the loop
if (firstRun == true){
temp.name = sc.nextLine();
}
else
temp.name = test;
System.out.println(temp.name);
temp.date = sc.nextLine();
if (temp.date.isEmpty()){
System.out.println("shit is empty yo");
}
temp.timeSpent = sc.nextInt();
temp.videosWatched = sc.nextInt();
temp.className = className;
studArr[studCounter] = temp;
studCounter++;
sc.nextLine();
test = sc.nextLine();
firstRun = false;
}
}
}
}
class Student {
public String name;
public String date;
public String className;
public int timeSpent;
public int videosWatched;
}
I don't need an exact answer, but should I be looking into a different tool then Scanner? Is there a method I can research?
Thanks for any assistance.
I came up with the following solution. Scanner is a fine tool for the job. The tricky part is that you have to sort of look ahead to see if you have a blank line or a date to know if you have a student or a class.
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;
public class Parser {
private static String nextLine(Scanner sc) {
String line;
while (sc.hasNext()) {
if (!(line = sc.nextLine()).isEmpty()) {
return line;
}
}
return null;
}
public static ArrayList<Student>[] parseFile(String fileName) {
File file = new File(fileName);
try (Scanner sc = new Scanner(file)) {
int numClasses = sc.nextInt();
String className = nextLine(sc);
ArrayList<Student>[] classList = new ArrayList[numClasses];
for (int i = 0; i < numClasses; i++) {
classList[i] = new ArrayList<>();
while (true) {
String studentOrClassName = nextLine(sc);
if (studentOrClassName == null) {
break;
}
String dateOrBlankLine = sc.nextLine();
if (dateOrBlankLine.isEmpty()) {
className = studentOrClassName;
break;
}
int timeSpent = sc.nextInt();
int videosWatched = sc.nextInt();
classList[i].add(new Student(className, dateOrBlankLine, studentOrClassName, timeSpent,
videosWatched));
}
}
return classList;
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return new ArrayList[0];
}
public static void main(String[] args) {
for (ArrayList<Student> students : parseFile("classList.txt")) {
if (!students.isEmpty()) {
System.out.println(students.get(0).className);
}
for (Student student : students) {
System.out.println(student);
}
}
}
static class Student {
public String className;
public String date;
public String name;
public int timeSpent;
public int videosWatched;
public Student(String className, String date, String name, int timeSpent,
int videosWatched) {
this.className = className;
this.date = date;
this.name = name;
this.timeSpent = timeSpent;
this.videosWatched = videosWatched;
}
public String toString() {
return name + '\n' + date + '\n' + timeSpent + '\n' + videosWatched + '\n';
}
}
}
Ask yourself, what does a Student contain? A name, date, number and number. So you want to do the following (not actual code) (format written in Lua code, very understandable. This means this will not run in Lua :P)
if line is not empty then
if followingLine is date then
parseStudent() // also skips the lines etc
else
parseClass() // also skips lines
end
end
What I am trying to do is read a text file which has this lines
232131231, random name, 23.3232
I only know how to read it as a String of the whole line. I don't know how to read them individually. This is my test codes.
main
public class JavaApplication9
{
int value1;
String value2;
double value3;
ArrayList<String> toBeSplit = new ArrayList();
String[] split;
ArrayList <Inventory> productList = new ArrayList<> ();
public long ReadFile(String sfile) throws IOException
{
int x = 0;
File inFile = new File(sfile);
BufferedReader reader = new BufferedReader(new FileReader(inFile));
String sline = null;
while ((sline=reader.readLine()) != null)
{
toBeSplit.add(x,sline);
x++;
}
reader.close();
return inFile.length();
}
public void splitString ()
{
int a = 0;
while (a<toBeSplit.size())
{
split = toBeSplit.get(a).split(",");
value1 = Integer.parseInt(split[0]);
value2 = split[1];
value3 = Double.parseDouble(split[2]);
productList.add(new Inventory (value1,value2,value3));
a++;
}
}
public void OutputLines ()
{
for (Inventory e : productList)
{
System.out.println (e.getBarcode() +"\t"+ e.getName()+"\t"+ e.getPrice());
}
}
public static void main(String[] args)
{
try
{
JavaApplication9 instance = new JavaApplication9 ();
instance.ReadFile("Products (1).csv");
instance.splitString();
instance.OutputLines();
}
catch (IOException e)
{
System.out.print ("Error");
}
}
}
and my Inventory class
public class Inventory
{
int barcode;
String name;
double price;
public Inventory (int bars,String pname,double prices)
{
barcode = bars;
name = pname;
price = prices;
}
public int getBarcode ()
{
return barcode;
}
public String getName ()
{
return name;
}
public double getPrice ()
{
return price;
}
}
Use split(String regex) to split the string. (See the javadocs for split())
Then you can individually parse each value in the way you want it.
Here is an example using your data:
String toBeSplit = "232131231, random name, 23.3232";
String[] split = toBeSplit.split(",");
int value1 = Integer.parseint(split[0].trim());
String value2 = split[1].trim();
double value3 = Double.parseDouble(split[2].trim());
I use trim() (See the javadocs for trim()) to get rid of the white space left behind after splitting.
Here's another way to do it without trim(): (Just add a space inside the split regex)
String toBeSplit = "232131231, random name, 23.3232";
String[] split = toBeSplit.split(", ");
int value1 = Integer.parseint(split[0]);
String value2 = split[1];
double value3 = Double.parseDouble(split[2]);
You can use split(String regex) for this.
Consider this simple example :
String mystr = "232131231, random name, 23.3232";
List<String> list = Arrays.asList(mystr.split(", "));
for(String str : list){
System.out.println(str);
}
Output :
232131231
random name
23.3232
If you wanted to get list as ArrayList particularly, you can use ArrayList(Collection list) version of ArrayList.
ArrayList list = new ArrayList(Arrays.asList(mystr.split(", ")));