Java storing both line number and value from a file - java

I have a set of data that look like this.
1:2:3:4:5
6:7:8:9:10
I have manage to use array list to store the information using a delimiter of ":".
However i would like to store the information of their line numbers together in the array list.
class test
{
String items;
String linenumber;
}
Example:
test(1,1)
test(2,1)
test(6,2)
test(7,2)
Here is my current code.
Scanner fileScanner = new Scanner(new File(fname));
fileScanner.useDelimiter("\n");
int counter = 0; String scounter;
String test;
String events;
while(fileScanner.hasNext())
{
events = fileScanner.next();
scounter = Integer.toString(counter);
Base obj = new Base(scounter, events);
baseArrayList.add(obj);
}
fileScanner.close();
I have try using delimiter "\n" and then trying to split out the string and it is not very successful.
Any advice would be appreciated.
public void Base_Seperator()
{
String temp, temp2;
String[] split;
String days, events;
for(int i = 0; i < baseArrayList.size(); i++)
{
temp = baseArrayList.get(i).events;
temp2 = baseArrayList.get(i).days;
split = temp.split(":");
}
}

Despite the code in #Alex's answer that may solve your problem, your attempt is almost close to get what you want/need. Now you only need to create Test instances and store them in a container, usually a List. I'll add the necessary code to start this from your code:
//it is better to return the List instead of declaring it as a static field
public List<Test> Base_Seperator() {
//try to declare variables in the narrower scope
//String temp, temp2;
//String[] split;
//String days, events;
//this variable must be recognized in all the paths of this method
List<Test> testList = new ArrayList<Test>();
for(int i = 0; i < baseArrayList.size(); i++) {
//these variables should only work within the for statement
String temp = baseArrayList.get(i).events;
String temp2 = baseArrayList.get(i).days;
String[] split = temp.split(":");
//you have splitted the String by :
//now you have every element between : as an item stored in split array
//go through each one and create a new Test instance
//first, let's create the lineNumber variable as String
String lineNumber = Integer.toString(i+1);
//using enhanced for to go through these elements
for (String value : split) {
//now, let's create Test instance
Test test = new Test(value, lineNumber);
//store the instance in testList
testList.add(test);
}
}
//now just return the list with the desired values
return testList;
}
Not part of your question, but some advices:
There are plenty other ways to write code to achieve the same solution (take #Alex's answer as an example). I didn't posted any of them because looks like you're in learning phase, so it will be better for you to first achieve what you're looking for with your own effort (and a little of help).
Not sure if you're doing it (or not) but you should not use raw types. This is, you should always provide a generic type when the class/interface needs it. For example, it is better to define a variable as ArrayList<MyClass> myClassList rather than ArrayList myClass so the class become parameterized and the compiler can help you to avoid problems at runtime.
It is better to always program oriented to interfaces/abstract classes. This means, it is better to declare the variables as an interface or abstract class rather than the specific class implementation. This is the case for ArrayList and List:
List<String> stringList = new ArrayList<String>();
//above is better than
ArrayList<String> stringList2 = new ArrayList<String>();
In case you need to use a different implementation of the interface/abstract class, you will have to change the object initialization only (hopefully).
More info:
What is a raw type and why shouldn't we use it?
What does it mean to "program to an interface"?
Looks like you want to store days instead of lineNumber in your Test instances:
//comment this line
//Test test = new Test(value, lineNumber);
//use this one instead
Test test = new Test(value, days);

First of all you don't need to keep line number info in the test object because it can be inferred from the ArrayList that holds them. If you must though, it should be changed to an int. So,
class test
{
ArrayList items<Integer>;
int linenumber;
public test(int line, String[] input){
items=new ArrayList();
linenumber=line;
//populate with the line read by the Scanner
for(int i=0; i<input.lenth; i++)
items.add(Integer.parseInt(input[i]));
}
}
I use an ArrayList inside test because you don't know how many elements you'll be handling. Moving on to the scanner
Scanner fileScanner = new Scanner(new File(fname));
// fileScanner.useDelimiter("\n"); You don't need this!
String tmp[];
int line=0; //number of lines
while(fileScanner.hasNext()) {
line++;
//this returns the entire line, that's why you don't need useDelimeter()
//it also splits it on '.' I'm not sure if that needs to be escaped but
//just to be sure
tmp=fileScanner.nextLine() . split(Pattern.quote("."));
baseArrayList.add(new test(line, tmp));
}
fileScanner.close();
Here I use test to store the objects you read, I'm not sure what Base is supposed to be.

A Java Bean/construct is required that will hold the day and the item together. The following code will read the text file. Each line will be converted to a List where finally the application will populate the List DayItems collection properly.
public class DayItem {
private int day;
private String item;
public int getDay() {
return day;
}
public void setDay(final int day) {
this.day = day;
}
public String getItem() {
return item;
}
public void setItem(final String item) {
this.item = item;
}
}
And main code
public class ReadFile {
private static final List<DayItem> dayItems = new ArrayList<DayItem>();
public static void main(String args[]) throws FileNotFoundException{
final BufferedReader bufferReader = new BufferedReader(new FileReader("items.txt"));
int lineNumber=0;
try
{
String currentLine;
while ((currentLine = bufferReader.readLine()) != null) {
lineNumber++;
List<String> todaysItems = Arrays.asList(currentLine.split(":"));
addItems(todaysItems,lineNumber);
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static void addItems(final List<String> todaysItems,final int day){
int listSize = todaysItems.size();
for(int i=0;i<listSize;i++){
String item = todaysItems.get(i);
DayItem dayItem = new DayItem();
dayItem.setDay(day);
dayItem.setItem(item);
dayItems.add(dayItem);
}
}
}

Related

parsing String to Ints

We have an assignment/project where we create a parking lot with several different objects then typically each week we add/improve on it. This week we were given a .txt file with lines that look like this "Bicycle%4%2%ABC40%false" or "Auto%22%7%ABC21%false". Each % is used as a delimiter denoting a separate attribute (speed, passenger capacity, serial number, and boolean lock status for bikes) for the respective object (car or bicycle).
We need to read through the file and create a new object in an array with that line using split. What I'm having trouble with is taking the number which is currently a string, parsing it as an int or boolean, then adding that to the new Bicycle (or Auto). Just can't seem to get the syntax right.
Also wondering if my "if" logic is right for if it says Bicycle to start creating a bicycle?
Update:
I think I have the parsing issue figured out, but now it's saying that it can't find my attributes for bicycle... saying "Cannot find symbol" So close!
Here's my code:
public class Driver
{
private static Object myBicycle;
private static Object myAuto;
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws FileNotFoundException
{
Scanner scan = new Scanner(new File("Vehicles.txt"));
ArrayList<Object> myVehicles = new ArrayList<Object>();
while (scan.hasNext())
{
String line = scan.nextLine();
String [] data = line.split("%");
if (data[0].equals("Bicycle"))
{
speed = (Integer.parseInt(data[1]));
PassCap = (Integer.parseInt(data[2]));
serialNumber = (Integer.parseInt(data[3]));
locked = (Boolean.parseBoolean(data[4]));
brand = Brand.randomBrand();
Bicycle myBicycle = new Bicycle(speed, PassCap, serialNumber, locked, brand);
myVehicles.add(myBicycle);
}
I'm not sure what your implementation is, but you could try something like this:
public static void main(String[] args) throws FileNotFoundException
{
Scanner scan = new Scanner(new File("/home/buddha/MYDRIVE/exploring/java/src/Vehicles.txt"));
ArrayList<String> myVehicles = new ArrayList<String>();
while(scan.hasNext()) {
String line = scan.nextLine();
String[] data = line.split("%");
if (data[0].toLowerCase().equals("bicycle")) {
System.out.println(Integer.parseInt(data[1]));
System.out.println(Integer.parseInt(data[2]));
System.out.println(data[3]);
System.out.println(Boolean.parseBoolean(data[4]));
}
else if (data[0].toLowerCase().equals("auto")) {
System.out.println(Integer.parseInt(data[1]));
System.out.println(Integer.parseInt(data[2]));
System.out.println(data[3]);
System.out.println(Boolean.parseBoolean(data[4]));
}
}
}
and just like the setter functions, you can create getter functions and check if the values have been correctly stored.
So, this line:
String [] data = line.split("%");
...takes strings like this:
"Bicycle%4%2%ABC40%false" or "Auto%22%7%ABC21%false"
and turns them into arrays of strings like this:
data[0] : `Bicycle` or `Auto`
data[1] : `4` or `22`
data[2] : `2` or `7`
data[3] : `ABC40` or `ABC21`
data[4] : `false` or `false`
So now you just need to parse those strings into their int and bool equivalents:
speed = Integer.parseInt(data[1]);
passCap = Integer.parseInt(data[2]);
serialNumber = data[3]; // This is a string, right?
locked = Boolean.parseBoolean(data[4]);
If serialNumber is a numeric, then you probably only want the numeric part at the end (e.g. "21" vs "ABC21"):
serialNumber = Integer.parseInt(data[3].Substring(3));

Dynamic ArrayList fields

I have an assingment for school and I am having trouble with some ArrayLists. I have an input file which has one entry at every line. This entry has an integer and up to four strings. This input file is about locations that a film is filmed. The integer is the movieID in my case and the strings are the locations. However not every film has 4 locations which means that when my program tries to load the file it returns an error because it expects 5 fields at every row and this never happens because I have movies with 1 or 2 or the locations. I use a data loader class because I have to load several different files. My other files have a specific number of entries and fields at each row so loading those isn't a problem. The load process is done by adding the file into an array list and then creating the objects needed. I know that I need the program somehow to understand the empty fields and maybe handle them dynamically, for example a movie has 3 locations so the 4th field is empty, but I haven't figured it out yet. Any suggestions? Thank you!
This is my LocationsLoader class.
package dataLoader;
import java.util.ArrayList;
import dataModel.Locations;
public class LocationsLoader extends AbstractFileLoader<Locations>{
public int constructObjectFromRow(String[] tokens, ArrayList<Locations> locations) {
int movieID;
List<String> loc = new List();
movieID = Integer.parseInt(tokens[0]);
loc = tokens[]; // What goes here?
Locations l;
l = new Locations(movieID, loc);
locations.add(l);
System.out.println(l);
//System.out.println(locations.toString());
return 0;
}
}
And this is my Locations class:
package dataModel;
public class Locations {
private int movieID;
private List<String> loc;
public Locations(int otherMovieID, List<String> otherLocations) {
this.movieID = otherMovieID;
this.loc = otherLocations;
}
public int getMovieID() {
return movieID;
}
public void setMovieID(int id) {
this.movieID = id;
}
public String getLocations(int index) {
return loc.get(index);
}
}
}
You fill an array here
String[] tokens = new String[numFields];
for (int i = 0; i < numFields; i++) {
tokens[i] = tokenizer.nextToken();
}
but arrays are fixed length, there's really no reason to use them if you can have fewer values. Fill a list instead.
List<String> tokens = new ArrayList<>();
while (tokenizer.hasNextToken()) {
String token = tokenizer.nextToken().trim();
if (!token.isEmpty()) {
tokens.add(tokenizer.nextToken());
}
}
In fact, I'm not sure why you would need to give the reader the number of expected tokens at all.
But as Dodgy pointed out, you might as well use String#split:
String[] tokens = line.split(delimiter);
which will yield empty Strings as well, but you can just ignore those in your constructObjectFromRow function.

How can i display my accessor (instance array) using Java? Code included

Not able to print the toString method, would like to be able to print the accessor and am not sure what the issue is. Am I not storing the array as an instance properly? I'd like to access the array in future methods so it is important for it to be stored as an instance.
public class j {
private double[] s;
public j() throws FileNotFoundException {
File in = new File("file.txt");
Scanner inScanFile = new Scanner(in);
int lines = inScanFile.nextInt();
s = new double[lines];
}
public double getXintercept(){
return s[2];
}
public String toString() {
double c = getXintercept();
System.out.println(c);
String descrip = "";
descrip = "kiki" + c; //want this to display and it won't
return descrip;
}
}
Create the object of this class in main method and then print the object using
System.out.println(yourobject);

Check through an ArrayList if it contains a String. If it doesn't, add that String

Edit
Many users are commenting that the Class Word is useless, which is probably true in this case. The reason I added it, is because I need it later on in the program.
This program has 3 classes - WordList, Word and a test class. I'm trying to get the method 'readBook' to read through a file, and send every word over to the method 'addWord'. Method addWord will check if the ArrayList allWords contains that word. If it doesn't, addWord will then add the word to an array, aswell as to send it over to class Word. When I run the program, nothing happens. I tried to print out allWords.size(), which returned 0.
Class WordList:
public class WordList {
String nextWord;
ArrayList<String> allWords = new ArrayList<String>();
public void readBook (String filename) throws Exception{
File file = new File(filename); //File has one word on each line.
Scanner innFile = new Scanner(file);
for (int i = 0; i<file.length(); i++){
if(innFile.hasNextLine()){
nextWord = innFile.nextLine();
addWord(nextWord);
}
}
}
private void addWord(String word){
for (String check : allWords){
if (!check.equalsIgnoreCase(word)){
allWords.add(word);
new Word(word);
}
else if(check.equalsIgnoreCase(word)){
System.out.println("The word allready exsist.");
}
else{
System.out.println("Something went wrong.");
}
}
}
Class Word:
public class Word {
String word;
ArrayList<String> allWords = new ArrayList<String>();
Word(String text){
word = text;
allWords.add(word);
System.out.print(allWords);
}
The test class:
public class TestClass {
public static void main (String[] args) throws Exception{
WordList list = new WordList();
list.readBook("path.../scarlet.text");
WordList newList = new WordList();
System.out.println(newList.numberOfWords());//A method printing out allWords.size()
}
}
You are populating allWords list of WordList class inside for (String check : allWords). Initially it would be empty hence it will never enter the for loop and allWords will never get populated. In turn new Word(word) will not be called and allWords of word class will be empty.
You have two issues with your code.
First, when that main loop (for (String check : allWords)) runs, allWords is going to be empty. Therefore, you will never add any elements to it, and that means it will always have a size of 0. To correct this, you probably need to add a boolean variable that gets set to true if you find the word. Then, after the loop, if the boolean variable is still false, add the word to the list.
Secondly, you've got allWords defined on two places: in your WordList class, and in your Word class. The WordList.allWords array is being updated correctly (as far as I can tell, once you fix the above mentioned issue). However, the Word.allWords array is not doing anything other than storing a single String value... twice (once in the array, once in a variable). The Word class isn't really doing anything useful, so I would opt to get rid of it.
I would get rid of the Word class completely, since it's currently not doing anything other than storing a String, which you could do with a String variable.
When the method addWord(String) is called it never enters the for loop because allWords is initially an empty ArrayList. Your call to "new Word(String)" is never reached.
I don't think you need allWords in both the Word class and the WordList class (?)
If you're just trying to get the unique words you can do this:
Set<String> words = new LinkedHashSet<>();
File file = new File("some file");
Scanner inFile = new Scanner(file);
for (int i = 0; i < file.length(); i++)
if (inFile.hasNextLine())
words.add(inFile.nextLine());
inFile.close();
then call
words.size()
to check if an array list contains a certain string you can use a for loop.
I'm not sure if this is the best way to go about it, but it should work.
for(int i = 0; i<yourArrayList.size(); i++){
if (yourArrayList.get(i).!contains(yourString)){
yourArrayList.add(yourString);
}
In test class try:
public static void main(String[] agrs) throws Exception {
WordList w = new WordList();
w.readBook("pathToMyFile"); // This way you access to readBook method
....
}
And add the word in method addWord when attribute allWords is empty.
private void addWord(String word){
if (allWords.isEmpty()) {
allWords.add(word);
} else {
// Your code
}
}

NullPointerException while indexing variable String parameters

I'm new to the idea of using an ellipsis. I'm almost certain my error is caused by improperly declaring or initializing "String[] authors", but I don't know how to do this an still have my setAuthors method work.
import java.util.*;
public class Book {
private String[] authors; //I'm guessing this line should end with "= new String..."
//but not sure how to w/o specifying an array dimension
private int authorsSize;
//Receives variable # of String parameters and indices them into String[] "authors"
public void setAuthors(String... authors) {
authorsSize = authors.length;
for(int i=0;i<authorsSize;i++)
this.authors[i] = authors[i];
}
//getAuthors method:
public String getAuthors(){
String s = "";
authorsSize = authors.length;
for(int i=0;i<authorsSize;i++)
s = s+authors[i] + ", ";
printAuthors = s;
return s;
}
The simplest approach would just be to clone the array:
public void setAuthors(String... authors){
this.authors = (String[]) authors.clone();
}
After all, you're overwriting the previous data anyway, and you can't know the size before the method call. You don't need the authorsSize variable at this point - you've got the authors array which knows its own length.
(If you were able to use immutable collections, you wouldn't even need to bother cloning, of course.)
EDIT: As noted in comments, this method will throw an exception if you pass in a null reference. You shouldn't automatically decide that this is a situation you should "handle" - it's entirely legitimate to document that the parameter must not be null. I would suggest documenting the behaviour around nullity either way.
Indeed, if you do this you might also want to initialize your instance field like this:
private String[] authors = new String[0];
That way you always know you'll have a non-null reference in that field, so you can use it with impunity. I would prefer this over having to check for null on every use.
you never initialized authors your array .
you need to initialize it before you use it .
String[] authors = new String[size];
//but not sure how to w/o specifying an array dimension
The best way is to use an List implementing classes as they are dynamic Arrays. i.e., you dont need to specify the size.
List<String> authors = new ArrayList<String>();
You have to currect your setAuthors method as described below
public void setAuthors(String... authors) {
if (authors != null && authors.length > 0) {
authorsSize = authors.length;
authors = new String[authorsSize];
for (int i = 0; i < authorsSize; i++)
this.authors[i] = authors[i];
}else{
this.authors = null;
}
}
Because the declaration of "private String[] authors" is before that of "public void setAuthors(String... authors)", you can not use the format like "String[] authors = new String[authorsSize]". This will make the size of authors always be 0.
The better way is to use the dynamic initialization:
List authors = new ArrayList();
Then use this.authors.add(authors[i]) to pass parameters.
you could also adjust your code like so:
import java.util.*;
public class Book{
private String[] authors;
private int authorsSize;
public void setAuthors(String... authors){
//check for null, you could also set this.authors = new String[] if you prefer.
if(authors == null){
this.authors = null;
}else{
authorsSize = authors.length;
//also add this line...
this.authors = new String[authorsSize];
for(int i=0;i<authorsSize;i++)
this.authors[i] = authors[i];
}
}
public String getAuthors(){
if(authors == null){
return ""; //could also return null here if you would prefer
}
StringBuilder s = new StringBuilder();
authorsSize = authors.length;
for(int i=0;i<authorsSize;i++){
if(i > 0)
s.append(",");
s.append(authors[i]);
}
//printAuthors = s;
return s.toString();
}
}

Categories

Resources