java.lang.IndexOutOfBoundsException: Invalid index 5, size is 5 - java

This error occurs sometimes and sometimes it works properly. I really can't understand what the problem is.
int length = CitiesInfos.citiesOnTheRoad.length;
for (int i = 0; i < length; i++)
{
HashMap<String,String> temp=new HashMap<String, String>();
temp.put(FIRST_COLUMN, CitiesInfos.citiesOnTheRoad[i]);
if (CitiesInfos.roadWorkArrayList.get(i)!=null)
{
temp.put(SECOND_COLUMN, CitiesInfos.weatherArrayList.get(i).getCelcius() + ", " +
CitiesInfos.weatherArrayList.get(i).getWeatherStatus());
}
else
{
temp.put(SECOND_COLUMN, " ");
}
}
This is the line to which logCat directs. What can the problem be?

increment variable i loops from 0 to citiesOnTheRoad.length - 1, however, you also use i as an index to two other ArrayList variables: weatherArrayList and roadWorkArrayList, how are you certain they are the correct size?
I added a check that will prevent the crash you are receiving, but I caution you to take a closer look at your code instead of putting this band-aid on it.
int length = CitiesInfos.citiesOnTheRoad.length;
for (int i = 0; i < length; i++)
{
HashMap<String,String> temp=new HashMap<String, String>();
temp.put(FIRST_COLUMN, CitiesInfos.citiesOnTheRoad[i]);
if(i < CitiesInfos.roadWorkArrayList.size()
&& i < CitiesInfos.weatherArrayList.size()
&& CitiesInfos.roadWorkArrayList.get(i)!=null)
{
temp.put(SECOND_COLUMN, CitiesInfos.weatherArrayList.get(i).getCelcius() + ", " + CitiesInfos.weatherArrayList.get(i).getWeatherStatus());
}
else
{
temp.put(SECOND_COLUMN, " ");
}
}

As James Wierzba has mentioned, you are using the same control variable for the array lists in the loop and that is your problem.
You need to ensure that there are enough items before you try to retrieve an element.
A few suggestions:
it seems you are storing related data in two arrays, you are better of grouping this data together inside a class e.g. City.
You could then have the cities on the road array contain a number of city objects each storing information about the weather in that city.
I would also suggest that you do not have your arrays as public variables, you should have them as private or protected and use getters/setters to access them.

Related

The content of an array is suspiciously doubled

I have been building an app that simulates the way a printer works. While designing the app, I have created the method below that splits a String content depending on the number of pages required. All the function seems to process the data correctly but I don't know why the method keeps doubling the content of an array it's supposed to return. Here's the method.
public ArrayList<String> splitContentIntoPages(){
int startPosition = 0;
int endIndexCalc = 0;
for(int i=0; i<getPages(); i++){
if((getContent().length() - endIndexCalc) >= getSize().getCapacity()){
System.out.println("Start " + startPosition);
endIndexCalc = startPosition + (getSize().getCapacity());
this.pagesContent.add(getContent().substring(startPosition, endIndexCalc));
startPosition += getSize().getCapacity();
System.out.println("End " + endIndexCalc);
}else{
this.pagesContent.add(getContent().substring(startPosition));
}
}
System.out.println("Size of the array " + this.pagesContent.size() + " getPages() " + getPages() + "");
for(int i=0; i<this.pagesContent.size(); i++){
System.out.println("The content :" + this.pagesContent.get(i));
}
return this.pagesContent;
}
I need some fresher eye on the issue. I have spent too much time on that trying to understand what's wrong. Thanks a lot guys!
Here's the version without debugs
public ArrayList<String> splitContentIntoPages(){
int startPosition = 0;
int endIndexCalc = 0;
for(int i=0; i<getPages(); i++){
if((getContent().length() - endIndexCalc) >= getSize().getCapacity()){
endIndexCalc = startPosition + (getSize().getCapacity());
this.pagesContent.add(getContent().substring(startPosition, endIndexCalc));
startPosition += getSize().getCapacity();
}else{
this.pagesContent.add(getContent().substring(startPosition));
}
}
return this.pagesContent;
}
this is the test entry extraxt. Basically the method aboe is processing the string of chars
that's the outcome. Basically, the string is supposed to be split into the number of pages - in this case 2. However, the array that is holding the split element of the strings holds 4 pieces of strings instead of two. It's all doubled. And I have no idea why
Either clear this.pagesContent at the beginning of splitContentIntoPages() or create new ArrayList<String> newA = new ArrayList<String>() at the beginning, add everythig to this new arrayList and at the end of splitContentIntoPages() do this.pagesContent = newA

Search and remove item from array

Does anyone why when the search value matches a value stored in array it doesn't remove that item?
String titles = "";
String lengths = "";
for (int i = 0; i < numOfSongs; i++) {
titles += songTitles[i] + " ";
lengths += songLengths[i] + " ";
}
String search = JOptionPane.showInputDialog("Enter a song title to remove it or -1 to end:");
while (!search.equals("-1")) {
for (int i = 0; i < numOfSongs; i++) {
if (search.equalsIgnoreCase(songTitles[i])) {
songTitles[i] = songTitles[i + 1];
}
}
numOfSongs--;
JOptionPane.showMessageDialog(null, "**Current Playlist**" + "\nSong titles: " + titles + "\nSong lengths: " + lengths);
search = JOptionPane.showInputDialog("Enter a song title to remove it or -1 to end:");
}
Many things are wrong with this code:
You never update titles and lengths inside your while loop, so whatever happens inside has no effect on what's printed in the dialog
When you find song title to remove, you copy the next song title to the current one, but don't copy anything else, so [a, b, c, d] will after removing b change to [a, c, c, d] - you need to shift everything behind the deleted element left by one position
When you find song title to remove, you assume the i+1th position is valid - this isn't true if you remove the last song on the list, that would either fail with ArrayIndexOutOfBounds exception or copy some garbage from behind the currently valid playlist
You're never updating songLengths array
Concatenating strings in a loop using += is very ineffective - use StringBuilder instead
Sorry this took a while, but hopefully it's pretty comprehensive.
I am assuming that song title and song length are supposed to correspond with one another, so that if you remove the title you also remove the length? It may be good to create a class, e.g. Song, which has a field for both title and length. There are more methods you can add, e.g. setters, default constructor, etc. You can also include more fields like Song Artist, year, etc. I'm just including those required for your program to run.
I'll use red's suggestion of an ArrayList, so you can see what they meant (in case you haven't learned what that is)
public class Song {
String title; //these are known as fields, or instance variables
String length;
public Song(String title, String length) {
this.title = title;
this.length = length;
}
public String getTitle() {
return title;
}
public String getLength() {
return length;
}
//you can format this differently. Just keeping it simple though. If you don't include toString() method in this class, you will run into some problems if you try to print the object itself.
public String toString() {
return "title = " + title + " length = " + length + "\n";
}
From here, in your main method you can do...
ArrayList<Song> playlist = new ArrayList<>();
//here, inside a do-while loop, get input for each song, then store into strings, let's call them songTitle and songLength. I'm not showing this step since I don't know where you want the input to come from, but I'm sure you can figure this bit out. ;)
Then we create objects and add them to your list like so:
Song song = new Song(songTitle, songLength); //creates a new object with arguments songTitle and songLength
playlist.add(song); //adds object to array list.
Once you have your playlist set up, we return to your question regarding song removal, and here is where Lists(there are different ones you can use)/Objects really make things far simpler.
Iterator<Song> songIt = playlist.iterator();
while (!search.equals("-1") && songIt.hasNext()) {
if (search.equalsIgnoreCase(songIt.next().getTitle())) {
songIt.remove();
}
}
And printing is simple too.
for (int i = 0; i < playlist.size(); i++) {
System.out.println(playlist.get(i);
}
-EDIT-
To put into perspective, here is what you would have to do for removal in your program using array and without objects.
int removeCount = 0;
while (!search.equals("-1")) {
for (int i = 0; i < songTitles.length; i++) {
if (search.equalsIgnoreCase(songTitles[i])) {
for (int j = i; j < songTitles.length - 1; j++) {
songTitles[j] = songTitles[j + 1];
songLengths[j] = songLengths[j + 1];
removeCount ++;
}
}
}
}
String remainingTitles[] = new String[songTitles.length - removeCount];
String remainingLengths[] = new String[songTitles.length - removeCount];
for (int i = 0; i < temp.length; i++) {
remainingTitles[i] = songTitles[i];
remainingLengths[i] = songLengths[i];
}
Suffice it to say, this is much more ugly, and there's many more places where you can make a stupid mistake that may or may not throw an exception.

How do I subtract some elements from one array which (element) are already in another array?

I have two different arrays and they both contain the same type of element. The elements are obtained from user input. And the arrays can store fixed size of element.
*Let's say that fisrt one is basically an arrayList and it adds the user input into the list.
The second one is simply an array which also gets value from user input. All the elements of second array are also contained in the first array and the length of this array is less than the first array*
Now I want to print an array which is the result of first array-second array.
This is the program I am working on right now. You may avoid this coding just to give me a theoritical concept for doing that.
package issuetracking;
import java.util.*;
public class IssueTrackingObject {
ArrayList<String> crIss = new ArrayList<String>();
Scanner input = new Scanner(System.in);
boolean crIss_bool;
int numOfSolvedIss;
private String[] solvedIss;
//lets user create some issues and add them into an arrayList
public void createIssue() {
System.out.println("Enter 5 issues: ");
for (int i = 0; i < 5; i++) {
System.out.println("Issue " + (i + 1 + ": "));
crIss_bool = crIss.add(input.nextLine());
}
}
//Let user mark some issues as solved (which are already in the list that the user has just created)
public void solvedIssue() {
System.out.println("How many solved issue you have(Must be less than 5): ");
numOfSolvedIss = input.nextInt();
solvedIss = new String[numOfSolvedIss];
for (int k = 0; k < numOfSolvedIss; k++) {
System.out.print("Enter solved issue(REMEMBER THAT THE SOLVED ISSUE MUST BE FROM ONE OF THEM YOU ALREADY HAVE CREATED)no. " + (k + 1) + ": ");
solvedIss[k] = input.next();
}
}
public void printUnsolvedIssue() {
//print out the elements of createIssue() that doesn't belong to the solvedIssue()
}
You can use a simple solution like this:
for (String solved : solvediss) {
if (solved != null) crIss.remove(solved);
}
This will remove all the Strings from the list that are in the array.
Of course, you could also do this.
crIss.removeAll(Arrays.asList(solvediss));
Go over your second array and use the remove method in arraylist to remove every element of second array from the first.
for (int i = 0; i < solvedIss.length; i++) {
crIss_bool = crIss.remove(solvedIss[i]);
}
Removing the elements might be the simplest method in this case, but it causes original list to change.
If you do not wish to have any destructive modification to the original list, you could perform a simple search like following.
for (String issue : crIss) {
bool isUnSolved = true;
for (String solvedIssue : solvedIss) {
if (issue.equals(solvedIssue)) {
isUnSolved = false;
break;
}
}
if (isUnSolved) {
// Print the 'issue' or do whatever you want to do with it.
}
}
Hope this helps.
Good luck.

java replace arraylist of strings

I can't seem to figure out how to replace an array list of strings.
ArrayList<String[]> Records
So within my for loop i want to replace a record can I keep getting this error.
The method set(int, String[]) in the type ArrayList is not applicable for the arguments (int, String)
for (int i = 0; i < Records.size(); i++) {
for (int j = 0; j < 2; j++) {
if (j == 0) {
if(!validateRecords(Records.get(i)[j].toString()))
{
Logging.info("Records could not be parsed " + Records.get(i)[j].toString());
Records.set(j, "CouldNotBeParsed");
}else
{
Logging.info(Records.get(i)[j].toString()+ " has been sanitized");
}
}
}
}
What is the proper way to replace this record using the Records.set() ?
You have an ArrayList of String[], and you are trying to give it a String. You need to be setting the index of the inner String[], not the outer ArrayList.
Do this instead:
Records.get(i)[j] = "CouldNotBeParsed";
Since you are not replacing the entire array, but changing a single entry in an existing array, you need to use a get() followed by an array write, instead of a set():
if(!validateRecords(Records.get(i)[j].toString())) {
Logging.info("Records could not be parsed " + Records.get(i)[j]);
Records.get(i)[j] = "CouldNotBeParsed";
} else {
Logging.info(Records.get(i)[j] + " has been sanitized");
}
Note that your if (j == 0) check inside the loop looks highly suspicious, because in effect it makes the loop on j entirely useless. You might as well write this:
for (int i = 0; i < Records.size(); i++) {
if(!validateRecords(Records.get(i)[0].toString())) {
Logging.info("Records could not be parsed " + Records.get(i)[0]);
Records.get(i)[0] = "CouldNotBeParsed";
} else {
Logging.info(Records.get(i)[0] + " has been sanitized");
}
}
Also note that calls of toString() are not necessary when you concatenate strings: Java compiler will insert them for you, and also take care of null values for you.
If you have an ArrayList<String[]> then it will hold only arrays of String. However you have the following line:
Records.set(j, "CouldNotBeParsed");
"CouldNotBeParsed" is a String, not a String[]. If you really want a String[] try this:
Records.set(j, new String[]{"CouldNotBeParsed"});

Using HashMaps Java

I'm writing a method that allows me to count how many times an element of type String shows up in a LinkedList of type Strings. my code shown below does not work. I keep getting index out of bounds in the line i commented on down below. Can't seem to find the bug
public int findDuplicate (LinkedList<String> e) {
int j = 1;
LinkedList<String> test = e;
while (!test.isEmpty()){
test = e;
String value = test.pop();
//Screws up here when i = 6
for(int i =0; i<=test.size() && test.get(i)!=null; i++){
String value3 = test.get(i);
if(e.get(i).equals(value) && i<=test.size()){
String value2 = test.get(i);
j++;
String Duplicate = e.get(i);
e.remove(i);
}
}
System.out.println(value + " is listed " + j + " times");
}
return j;
}
using hashmaps.. still doesn't work
public void findDuplicate (LinkedList e) {
Map<String,Integer> counts = new HashMap<String,Integer>();
while(!e.isEmpty()){
String value = e.pop();
for(int i =0; i<e.size(); i++){
counts.put(value, i);
}
}
System.out.println(counts.toString());
}
My code should go through the linked list find out how many times an element within the list appears and deletes duplicates from the list at the same time. Then prints the element and the number of times it appears in the list. I posted about this last night but didn't get a response yet. Sorry for the repost.
You are running off the end of the list. Change
for(int i =0; i<=test.size() && test.get(i)!=null; i++){
to
for(int i =0; i< test.size() && test.get(i)!=null; i++){
Valid indexes for a List (or an array) are 0 through size() - 1.
Regarding your hashmap example to count the duplicates:
#Test
public void countOccurrences() {
LinkedList<String> strings = new LinkedList<String>(){{
add("Fred");
add("Fred");
add("Joe");
add("Mary");
add("Mary");
add("Mary");
}};
Map<String,Integer> count = count(strings,new HashMap<String,Integer>());
System.out.println("count = " + count);
}
private Map<String, Integer> count(List<String> strings, Map<String, Integer> runningCount) {
if(strings.isEmpty()) {
return runningCount;
}
String current = strings.get(0);
int startingSize = strings.size();
while(strings.contains(current)) {
strings.remove(current);
}
runningCount.put(current, startingSize - strings.size());
return count(strings,runningCount);
}
If you want the original strings list preserved you could do
Map<String,Integer> count = count(new LinkedList<String>(strings),new HashMap<String,Integer>());
System.out.println("strings = " + strings);
System.out.println("count = " + count);
Check out google's guava collections which has a perfect class for maintaining a map and getting a count:
https://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#BiMap
Multiset<String> wordsMultiset = HashMultiset.create();
wordsMultiset.addAll(words);
// now we can use wordsMultiset.count(String) to find the count of a word
I hope you realize what the test = e statement is doing. After this statement executes both test and e refer to the same object.
If anyone of them modifies the list, the other sees it as they both are looking at the same object.
If this is not intended you need to clone the list before assigning it to another list reference.
This doesn't affect your out of bounds issue, but you are removing elements from your list while still evaluating it. If you remove an element, you should call i-- afterwards, or you skip the next entity (which is re-indexed) for evaluation.
Also of note regarding your code, I see you are trying to make a copy of your list, but standard assignment means test and e both point to the same instance. You need to use Collections.copy() see this SO thread on how to use the class.

Categories

Resources