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.
Related
I am a true beginner to programming, so forgive me.
I have a String Array filled with a set of quotes that I have a method randomly picking one to display on the screen. This all works perfectly, I'd like to take the next step now. I would like to have the ability to add text to this array that a user inputs on an Activity that I have created. I understand that Arrays are Immutable, but I am failing to figure out how to create an ArrayList, pre-fill it with my 50ish quotes and then have the ability to add more through the app later.
Here is the code I currently have...
public class FactBook {
public String[] mFacts = {
"Quote 1.",
"Quote 2.", };
public String getFact() {
String fact = "";
Random randomGenerator = new Random();
int randomNumber = randomGenerator.nextInt(mFacts.length);
fact = mFacts[randomNumber];
return fact;
}
References
ArrayList
Arrays
import java.util.ArrayList;
import java.util.Arrays;
public class FactBook {
// Public data members are not recommended.
// Make it at least protected and arrange controlled access to it
// by specific methods
public ArrayList<String> mFacts =
new ArrayList<String>(
Arrays.asList("Quote 1.", "Quote 2.")
)
};
public String getFact() {
String fact = "";
// Do you need to create a new Random every time?
// Perhaps creating it only once and storing it in a static
// (class wide) data member will be just as good: create it once,
// reuse it later.
Random randomGenerator = new Random();
int randomNumber = randomGenerator.nextInt(mFacts.size());
fact = mFacts.get(randomNumber);
return fact;
}
// how to add
public void add(String newQuip) {
// Don't accept null or "all-white character" quotes
if(null!=newQuip && newQuip.trim().length()>0) {
this.mFacts.add(newQuip);
}
}
}
Look at Arrays class.
It has a helper method exactly for those cases:
List<String> facts = Arrays.asList("string1", "string2", ...);
Here's a simple method that pre-populates an ArrayList with your values, and then allows you to add more values to it later on
private ArrayList<String> createPrePopulatedList() {
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("Quote 1.");
///Add any more you want to prepopulate like this
return arrayList;
}
You can call this method like so.
private ArrayList<String> myArrayList = createPrepopulatedList();
Now you can simply add whatever you want to it dynamically with add().
You should probably do some reading on Java data structures before you jump into Android programming. Here's some help with ArrayList https://www.tutorialspoint.com/java/java_arraylist_class.htm
I am new to Java and I am trying to do a calculation using values within a txt file. I have read the txt file, which has 3 tabs, each with three values
I have been able to read the file and get the columns as indices but cannot add the separate values into array. So I want three separate arrays
Read file method
public void read()
{
try
{
FileReader read = new FileReader(file);
String line = null;
while((line = FileReader.readLine()) != null)
{
a.add(line);
}
}
catch (FileNotFoundException e) {}
catch(IOException e) {}
}
Processing method
private void processor () {
for (String li : a)
{
String[] data = li.split("\\s");
Index = Double.parseDouble(data[0]);
Customers = Double.parseDouble(data[1]);
rateOfBuy = Double.parseDouble(data[2]);
}
}
I dont think you are thinking about your data structures correctly. If I were you I would think about this a little differently. To me it makes the most sense just to use a simple array. To handle the complexity of the three columns, I would create a new class called CustomerRate or something to that effect. I would then make the data into instance variables belonging to instances of that class. That way you could just have a simple array of CustomerRate objects and then access the data stored by each of those objects. This will probably be a lot simpler to deal with overall too.
I am not sure exactly what you are trying to accomplish but I'll do my best to help
You would create your new class to be something like this:
your new class:
//This is your new class
public class CustomerRate {
private int person;
private double rate;
//constructor
public CustomerRate(int person, double rate) {
this.person = person;
this.rate = rate;
}
//add appropriate getters and setters and whatever else you need
public double getRate() {
return rate;
}
}
Use the data your parse from your file to create new CustomerRate Objects. Create an array of your objects. Note that this is just an example with one entry with random numbers I'm going to use so you will have to get the loop and parse working:
//creating an example customer
CustomerRate customer1 = new CustomerRate(100, 0.5);
//create your collection to store your customer data that you will add/parse
List<CustomerRate> myList = new ArrayList<CustomerRate>();
//adds to list
myList.add(customer1);
//gets element at index and then grabs the rate
double exampleCustomerRate;
exampleCustomerRate = myList.get(0).getRate();
I coded this quickly so I may have made some mistake but I hope that gives you the general idea of what you should do.
You just need another ArrayList to store your rateOfBusiness. Something like this:
String file = "test.txt";
ArrayList<String> a = new ArrayList<String>();
ArrayList<Double> rateOfBusiness = new ArrayList<>(); //Define with your other fields
Then loop through your data and do the math while adding to the array
private void process () {
for (String li : a)
{
String[] data = li.split("\\t");
Index = Double.parseDouble(data[0]);
Customers = Double.parseDouble(data[1]);; //per year
rateOfBuy = Double.parseDouble(data[2]); //per year
rateOfBusiness.add(Customers*rateOfBuy); //Do math and store for that customer
}
}
Edit: Even though this solves your problem, I would look into learning some Object Oriented principles. IsaacShiffman (or Lvl 9 Oddish, or whatever his name is) has a start on how you would solve this going that direction. Makes your code a lot easier to follow and debug.
I am having issues with objects and classes.
I had to define two classes:
Course: a course has a code, an name and a number of credits
Teacher: a teacher has a first name and last name. He can be asked his full name.
So far so good, I got no issue with them, but I have to do next assignment which I was trying to do in the last 2 days and I could not find a proper answer:
Extend the code of the class teacher. A teacher also has a list of courses he can teach. Add an array of Courses to the code. Also add a function addCourse(Course aCourse) to the code. Courses can also be removed from teachers.
I could do everyting in my way but no clue on how to create the addCourse(Course aCourse) method.
Find below my coding, but it must be according to the method described:
public class Course {
private String courseCode;
private String courseName;
private String numberOfCredits;
public Course(String courseCode, String courseName, String numberOfCredits) {
super();
this.courseCode = courseCode;
this.courseName = courseName;
this.numberOfCredits = numberOfCredits;
}
public void print() {
System.out.println(courseCode + "\t" + courseName + "\t" + numberOfCredits);
}
public static void main(String[] args) {
Course[] courseArray = new Course[4];
System.out.println("Code" + "\t" + "Name" + "\t" + "Credits");
courseArray[0] = new Course("001", "Hist", "3");
courseArray[1] = new Course("002", "Phy", "3");
courseArray[2] = new Course("003", "Math", "3");
courseArray[3] = new Course("004", "Log", "3");
for (int i = 0; i < courseArray.length; i++) {
courseArray[i].print();
}
}
}
Arrays are fixed length collections of objects, so you'll need to decide how big your array should be. Let's call the length of your array MAX_COURSES. A more advanced solution might resize the array when required, but I get the impression this is beyond the scope of your course.
So you need to define the Course[] array as a field of your Teacher class. The syntax of array declarations is quite easy to research, so I won't put that in here. Just make sure your array length is equal to MAX_COURSES.
Now, to add courses to the array, you need to know where to put them. To keep track of the next free position of the array, the easiest thing to do is to declare a field in your class:
private int numCourses = 0;
Now, when you add a new course, insert the course into the index specified by numCourses. Make sure you increment numCourses after you've added the course.
Finally, you ought to test to see if your array is full before you agree to insert a new course into the array, i.e. check if numCourses is smaller than MAX_COURSES. If it's not, you need to throw an exception.
I would recommend using a collection (such as a List) rather than an array. The code would look something like:
public class Teacher {
private final String firstName;
private final String lastName;
private final List<Course> courses = new ArrayList<Course>();
public Teacher(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public void addCourse(Course course) {
courses.add(course);
}
}
Based on that example, you should be able to add the removeCourse method yourself, and any other method you need to operate on the list of courses.
If you want to return the list as an array, you could always convert it, e.g:
public Course[] getCourses() {
return courses.toArray(new Course[courses.size()]);
}
If you really need to use an array for the data structure based on your assignment, something you can try when adding and removing courses, is to construct a list from the array of courses, add or remove a course from that list, the convert the list back to an array of courses.
There's really 3 options here.
Option 1
If you're allowed to use List constructs:
private List<Course> courses = new ArrayList<Course>();
public void addCourse(Course aCourse)
{
if (aCourse == null)
{
return;
}
courses.add(aCourse);
}
Option 2
The uses arrays, but it doesn't scale. Assume that a teacher can only have a maximum of X courses, in my example 10:
// Yes, I stole Duncan's variable names
private final int MAX_COURSES = 10;
private int numCourses = 0;
private Course[] courses = new Course[MAX_COURSES];
public void addCourse(Course aCourse) {
if (aCourse == null)
{
return;
}
if (numCourses >= courses.length)
{
return;
}
courses[numCourses] = aCourse;
numCourses++;
}
Option 3
This is identical to the previous item, but is a bit smarter in that it can resize the array... by creating a new one using the static method Arrays.copyOf
// Yes, I stole Duncan's variable names
private final int MAX_COURSES = 10;
private int numCourses = 0;
private Course[] courses = new Course[MAX_COURSES];
public void addCourse(Course aCourse) {
if (aCourse == null)
{
return;
}
if (numCourses >= courses.length)
{
int size = courses.length * 2;
courses = Arrays.copyOf(courses, size);
}
courses[numCourses] = aCourse;
numCourses++;
}
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);
}
}
}
This might be a dumb question but its frustrating me. I am adding into my array list a object during a loop but outside of the loop, all of the array list is overwritten with the last element in the array. It goes something like this.
while(fin.hasNextLine())
{
String line = fin.nextLine();
String[] user = line.split(",");
r.add(new User(user[0], user[1]));
System.out.println(r.get(count).getName());
count++;
}
This gives me an output of something like this (USER1, USER2, USER3, etc.) during the loop.
However, right after the loop I now have an output of something like this (USER500, USER500, USER500).
while(fin.hasNextLine())
{
String line = fin.nextLine();
String[] user = line.split(",");
r.add(new User(user[0], user[1]));
System.out.println(r.get(count).getName());
count++;
}
for (int i =0; i < r.size(); i++)
{
System.out.println(r.get(i).getName());
}
I managed to verify that this is the class where I'm having the problem and only one other method uses the array list in this class which i commented out.
I'm going to have to put on my psychic debugging goggles, but I predict tht your User class looks like this:
public class User {
private static String name;
public User(String x, String somethingElse) {
name = x;
}
public String getName() {
return name;
}
}
Note that name is static. Therefore that's one variable - not one per instance of User. You want it to be an instance field, so that each User object has a different name variable.