How to update an element in an array? - java

How can I get the Observation method to increase a single element in the numberofObs array by 1, every time I use it?
I get this error: Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
public class Database {
private ArrayList <String> databaseOfBirds = new ArrayList<String>();
private int[] numberofObs = new int[databaseOfBirds.size()];
public void add(String name, String latinName) {
databaseOfBirds.add(name + "(" + latinName + ")");
}
public String Observation(String birdname){
for(int i = 0; i < databaseOfBirds.size(); i++) {
if(databaseOfBirds.get(i).contains(birdname)) {
numberofObs[i]++;
return "";
}
}
return "Is not a bird!";
}
}

When you create your numberofObs array it's length is zero, since at that point databaseOfBirds is empty. Unless you're growing the array in some unlisted code you'll get a NullPointerException the first time you find a bird.
You could fix this by making numberofObs a List:
private List<Integer> numberofObs = new ArrayList<>();
Then in your add method add the line:
numberofObs.add(0);
Finally, change
numberofObs[i]++;
to
numberofObs.set(i, 1 + numberofObs.get(i));

Implementation is wrong in 2 places:
numberOfObs assignment will trigger ArrayIndexOutOfBoundsException since you are not resizing it each time a new bird is added to database
you are not increasing anything on the matching bird counter
I am understanding you want to have a separate counter for each bird matched by Observation. Here you are (there are several approaches in terms of data structures, taking the one easiest to understand):
public class Database {
private List<String> databaseOfBirds = new ArrayList<>();
private List<Integer> numberofObs = new ArrayLidt<>();
public void add(String name, String latinName) {
databaseOfBirds.add(name + "(" + latinName + ")");
numberofObs.add(0);
}
public String Observation(String birdname){
for(int i = 0; i < databaseOfBirds.size(); i++) {
if (databaseOfBirds.get(i).contains(birdname)) {
numberofObs.set(i, numberofObs.get(i)+1);
System.out.println(numberofObs.get(i));
return "";
}
}
return "Is not a bird!";
}
}

I suggest using a Map instead of 2 Lists.
private Map<String, Long> birds = new HashMap<>();
Easier to manage. Unless memory is scarce, you probably don't want to use int[].

Related

ArrayList size resetting to 1 in a for loop

I am trying to find the index of a value in a nested ArrayList, but I need to find the position of the first ArrayList. I am receiving an error when I run this code:
public int findCity(String city) {
city = "\"" + city + "\"";
System.out.println(cityArray.size());
for (List<String> value : cityArray) {
String newCity = value.get(1);
if (newCity == city) return cityArray.indexOf(value);
}
return -1;
}
The problem happens in the line after the for loop:
String newCity = value.get(1);
It's telling me that index 1 is out of bounds for length 1. Any help is greatly appreciated!
I found the problem: I was using nextLine() to read the csv file, and it was creating a new array every time there was a space. This was a huge oversight on my part, but now I can start fixing the problem.
Once again, sorry for the inconvinience.
You're mixing up cityArray.size() and cityArray.get(1).size(), which can be completely different.
(You are also comparing strings with ==, which is likely to cause disaster. Use .equals.)
i think the problem is that you start counting from 1, but an ArrayList starts counting from 0. This is why the index is out of bounds.
You could try this:
String newCity = value.get(0);
Below code can help you ,though I did not understand your problem.
public static void main(String[] args) {
List<String> list1 = Arrays.asList(new String[]{"A","B"});
List<String> list2 = Arrays.asList(new String[]{"Y","Z"});
List<List<String>> cityArray = new ArrayList<>(2);
cityArray.add(list1);
cityArray.add(list2);
System.out.println(findCity("Z", cityArray));
}
public static int findCity(String city, List<List<String>> cityArray) {
System.out.println(cityArray.size());
for (List<String> value : cityArray) {
for(String newCity :value) {
if (newCity.equalsIgnoreCase(city)) {
return cityArray.indexOf(value);
}
}
}
return -1;
}

How to add an element in this ArrayList?

i've been trying to make this work but how can I add a fourth element
in this ArrayList "hourCounts"?
public class HourCounts {
private String[] hourCounts = {"One","Two","Three"};
public hourCounts() {
hourCount[3] = new String ("Four") ; // how do I write the code to add a
// new element that says "Four"?
}
public void countHours() {
int hour = 0;
while(hour < hourCounts.length) {
System.out.println(hour + ": " + hourCounts[hour]);
hour++;
}
}
}
The following example of using ArrayList should help you:
List<String> hourCounts = private List<String> hourCounts
= new ArrayList<>Arrays.asList("One", "Two", "Three"));
public hourCounts() {
hourCount.add(new String ("Four"));
}
ArrayList is one of the most popular implementations of List. List is something different than an Array ([]).
Arrays are fixed length. Lists are flexible. Thus, when you know the amount of elements to store, you should use an array. (e.g. String[]). If you don't know the size or you know that size will change from time to time (by adding and removing elements) it's recommended to use a List.
Also, remember that in Java, Strings aren't char[]. In fact, they store an array of chars in a certain field, but it's different from C or Python.
Java arrays have a fixed length (at time of construction), you might copy your current array to add another element. Like,
private String[] hourCounts = { "One", "Two", "Three" };
public hourCounts()
{
hourCounts = Arrays.copyOf(hourCounts, hourCounts.length + 1);
hourCounts[hourCounts.length - 1] = "Four";
}
But, I think you wanted a List like
private List<String> hourCounts = new ArrayList<>(Arrays.asList(
"One", "Two", "Three"));
public hourCounts() {
hourCounts.add("Four");
}
public void countHours() {
int hour = 0;
while (hour < hourCounts.size()) {
System.out.println(hour + ": " + hourCounts.get(hour));
hour++;
}
}
Finally, please follow Java naming conventions (and don't name the class the same as a field in that class).

Return String continuously - Data getting overwritten by ArrayList

Currently creating a tableview using JavaFX and came accross this problem where it would simply append the last element of the array (As all the other elements get overrwritten ..)
public void companyTable() {
for(CompanyData s: companydataList()){
companyDataTableView.getItems().setAll(s);
}
}
Where companyDataList is:
private List<CompanyData> companydataList(){
CompanyData company = new CompanyData("test",9,1);
for(String i : sim.getCompanyNames()) {
company.setPFCompanyName(i);
}
for(int j : sim.getCompanyValues()) {
company.setPFShareValues(j);
}
List<CompanyData> companydata = new ArrayList<>();
companydata.add(company);
return companydata;
}
The data gets added to this (Setters and getters of Strings)
private final StringProperty PFCompanyName;
private final IntegerProperty PFShareValues;
public CompanyData(String CompanyName, int ShareValue, int ClosingPence) {
this.PFCompanyName = new SimpleStringProperty(CompanyName);
this.PFShareValues = new SimpleIntegerProperty(ShareValue);
}
public String getPFCompanyName() {
return PFCompanyName.get();
}
public StringProperty PFCompanyNameProperty() {
return PFCompanyName;
}
public void setPFCompanyName(String PFCompanyName) {
this.PFCompanyName.set(PFCompanyName);
}
public int getPFShareValues(int j) {
return PFShareValues.get();
}
public IntegerProperty PFShareValuesProperty() {
return PFShareValues;
}
public void setPFShareValues(int PFShareValues) {
this.PFShareValues.set(PFShareValues);
}
Currently the output is:
CompanyName CompanyValue
Samsung 1093
But what I desire is:
CompanyName CompanyValue
Nokia 3
Apple 1
HTC 9
Samsung 1093
The method setAll(...) replaces all the elements currently in the list with the ones you provide (it "sets them all"). So each time you iterate through your loop, you replace all the elements with the current one. At the end you will just have one element in the table.
An ObservableList is a subtype of the standard java.util.List, so you can call any of the standard list methods. E.g. you can just add each element instead:
public void companyTable() {
for(CompanyData s: companydataList()){
companyDataTableView.getItems().add(s);
}
}
Of course, you don't really need to write the loop yourself, you can just add them all:
public void companyTable() {
companyDataTableView.getItems().addAll(companydataList());
}
or, if it's what you need, set them all:
public void companyTable() {
companyDataTableView.getItems().setAll(companydataList());
}
Furthermore, your companydataList() method only creates one CompanyData instance, and then constantly changes it. Here is your current implementation, with comments explaining what each line you wrote does:
private List<CompanyData> companydataList(){
// create a single instance:
CompanyData company = new CompanyData("test",9,1);
// repeatedly change the name of that instance:
for(String i : sim.getCompanyNames()) {
company.setPFCompanyName(i);
}
// repeatedly change the value of that instance:
for(int j : sim.getCompanyValues()) {
company.setPFShareValues(j);
}
// create an empty list:
List<CompanyData> companydata = new ArrayList<>();
// add one object to the list
companydata.add(company);
// return the list containing the single object:
return companydata;
}
You need to create a CompanyData instance for each of the name/value pairs, and add each instance to the list. Assuming sim.getCompanyNames() and sim.getCompanyValues() return lists (or arrays; I will assume they are lists) of the same length, you need to do something like
private List<CompanyData> companydataList(){
List<String> companyNames = sim.getCompanyNames();
List<Integer> companyValues = sim.getCompanyValues();
List<CompanyData> companydata = new ArrayList<>();
for (int i = 0 ; i < companyNames.size(); i++) {
String name = companyNames.get(i);
int value = companyValues.get(i);
CompanyData company = new CompanyData();
company.setPFCompanyName(name);
company.setPFShareValues(value);
companydata.add(company);
}
return companydata;
}
Obviously, it would be far more sensible to have sim, which I assume is some kind of data accessor, return a List<CompanyData> directly in the first place, instead of two different lists for the different properties.

Why am I unable to assign an embedded ArrayList<Integer> to a locally declared ArrayList<Integer>?

Sorry if the title is not clear, I'm not very good with programming jargon.
I have 2 string ArrayLists and an integer ArrayList obtained from one method which is passed to a separate method through the collection LinkedHashMap< String, List< String>>. However, when I try to set the integer ArrayList into a empty ArrayList declared in the receiving method, it shows the syntax error: "incompatible types: List< String> cannot be converted to List< Integer>".
Starter Method:
public static void main(String[] args) {
try{
LinkedHashMap lhm = new LinkedHashMap();
List<String> listEPC = new ArrayList<String>();
List<String> listTimeStamp = new ArrayList<String>();
List<Integer> listAntenna = new ArrayList<Integer>();
String tagID = "EQ5237";
String TimeStampStr = "12:23:22";
int tagAntenna = 2;
listEPC.add(tagID);
listTimeStamp.add(TimeStampStr);
listAntenna.add(tagAntenna);
lhm.put("epcs", listEPC);
lhm.put("timestamps", listTimeStamp);
lhm.put("antennas", listAntenna);
insertData insert = new insertData();
insert.insertData(lhm); //send map with values to new method
}catch(Exception e){
e.printStackTrace();
}
}
Receiving Method:
public class insertData {
public void insertData(LinkedHashMap<String, List<String>> readMap) {
List<String> listEPC = new ArrayList<String>();
List<String> listTimeStamp = new ArrayList<String>();
List<Integer> listAntenna = new ArrayList<Integer>();
String EPC = null;
String TimeStamp = null;
Integer Antenna = null;
listEPC = readMap.get("epcs");
listTimeStamp = readMap.get("timestamps");
listAntenna = readMap.get("antennas"); //error message here
for(int i=0; i<readMap.size(); i++){
EPC = listEPC.get(i);
TimeStamp = listTimeStamp.get(i);
Antenna = listAntenna.get(i);
System.out.println("Entry " + i );
System.out.println("Values: " + EPC + TimeStamp + Antenna);
}
}
}
This code works only if I change all instances of integers to strings, which is not what I would like in my actual code. Why is it so and how do I work around it?
You can't assign a List<String> to a List<Integer>. The elements are fundamentally different types.
You would need to construct a new List:
List<Integer> listOfIntegers = new ArrayList<>();
for (String entry : listOfStrings) {
listOfIntegers.add(Integer.valueOf(entry);
}
Of course, you also need to handle the possibility that elements of the list cannot be parsed as integers.
However, you are just throwing away type information by stuffing everything into a single map. It would be better to pass the three lists separately:
insertData(listEPC, listTimestamp, listAntenna);
and then you can have different list types in the method signature:
void insertData(
List<String> listEPC,
List<String> listTimestamp,
List<Integer> listAntenna) { ... }
I am going to include the proper answer at the bottom, but in regards to your question title, you'll have to change your method signature to:
LinkedHashmap<String, List<?>> readMap;
Then either cast the lists, which will cause an unsafe cast. eg.
List<String> listEPC = (List<String>)readMap.get("epcs");
Or cast the object.
List<?> listEPC = readMap.get("epcs");
Then in the loop cast.
EPC = (String)listEPC.get(i);
Note, these are not good solutions.
What you should have is one List that contains an object with all of the data's you need.
I can imagine the thought process went something along these lines, "I have these things, and they contain two strings and an integer. I will create a variable for each." Then you ask the question, "How do I create a collection of these things?"
The wrong answer to this question is, "I will make a list for each value, and match associated values by index." The correct answer is, "I will create a class to represent my data, and store that in a list." This is the basic essence of object orient programming (welcome to java).
First we design the class:
class EPCThing{
String EPC;
String timeStamp;
int Antennas;
public EPCThing(String tagId, String timeStamp, int antennas){
EPC=tagId;
this.timeStamp = timeStamp;
Antennas = antennas;
}
#Override
public String toString(){
return "Values: " + EPC + TimeStamp + Antenna
}
}
Now your program's main method will be something like.
List<EPCThing> things = new ArrayList<>();
String tagID = "EQ5237";
String TimeStampStr = "12:23:22";
int tagAntenna = 2;
EPCThing thing = new EPCThing(tagID, TimeStampStr, tagAntenna);
things.add(thing);
insertData insert = new insertData();
insert.insertData(things);
Then we can fix your insertData method
public void insertData(List<EPCThing> things) {
for(int i=0; i<things.size(); i++){
System.out.println("Entry " + i );
System.out.println("Values: " + things.get(i));
}
}

Using a string to write to an array

Attempting to tidy up code, originally I was using this method of writing to arrays, which is ridiculously long when I have to repeat it 20 times
if (ant.getAntNumber() == 3)
{
numbers3.add(ant.getCol());
numbers3y.add(ant.getRow());
}
if (ant.getAntNumber() == 4)
{
numbers4.add(ant.getCol());
numbers4y.add(ant.getRow());
}
I attempted to use a for loop to do it but I cant figure out how to add to the array using the string value, because it thinks its a string rather than trying to use the array
for (int j = 0; j<maxAnts; j++)
{
String str = "numbers" + j;
String str2 = "numbers" + j + "y";
//this part doesnt work
str.add(ant.getCol());
}
Any suggestions would be helpful
In Java, you cannot use the value of a String object to reference an actual variable name. Java will think you're attempting to to call add on the String object, which doesn't exist and gives you the compiler error you're seeing.
To avoid the repetition, you need to add your Lists to two master lists that you can index.
In your question, you mention arrays, but you call add, so I'm assuming that you're really referring to Lists of some sort.
List<List<Integer>> numbers = new ArrayList<List<Integer>>(20);
List<List<Integer>> numbersy = new ArrayList<List<Integer>>(20);
// Add 20 ArrayList<Integer>s to each of the above lists in a loop here.
Then you can bounds-check ant.getAntNumber() and use it as an index into your master lists.
int antNumber = ant.getAntNumber();
// Make sure it's within range here.
numbers.get(antNumber).add(ant.getCol());
numbersy.get(antNumber).add(ant.getRow());
How about this?
Ant[] aAnt = new Ant[20];
//Fill the ant-array
int[] aColumns = new int[aAnt.length];
int[] aRows = new int[aAnt.length];
for(int i = 0; i < aAnt.length; i++) {
aColumns[i] = aAnt[i].getCol();
aRows[i] = aAnt[i].getRow();
}
or with lists:
List<Integer> columnList = new List<Integer>(aAnt.length);
List<Integer> rowList = new List<Integer>(aAnt.length);
for(Ant ant : aAnt) {
columnList.add(ant.getCol());
rowList.add(ant.getRow());
}
or with a col/row object:
class Coordinate {
public final int yCol;
public final int xRow;
public Coordinate(int y_col, int x_row) {
yCol = y_col;
xRow = x_row;
}
}
//use it with
List<Coordinate> coordinateList = new List<Coordinate>(aAnt.length);
for(Ant ant : aAnt) {
coordinateList.add(ant.getCol(), ant.getRow());
}
A straight-forward port of your code would be to use two Map<Integer, Integer> which store X and Y coordinates. From your code it seems like ant numbers are unique, i.e., we only have to store a single X and Y value per ant number. If you need to store multiple values per ant number, use a List<Integer> as value type of the Map instead.
Map<Integer, Integer> numbersX = new HashMap<Integer, Integer>();
Map<Integer, Integer> numbersY = new HashMap<Integer, Integer>();
for(Ant ant : ants) {
int number = ant.getAntNumber();
numbersX.put(number, ant.getCol());
numbersY.put(number, ant.getRow());
}

Categories