How can I fix this exception - java

Here is my code to distinguish the differences between two txt files. The only problem is i get an out of bounds exception if i dont subtract 1 from the arrayList, so right now it is not running for all of the elements, how do i fix this?
import java.io.*;
import java.util.*;
public class myfilereader
{
public static void main (String[] args) throws java.io.IOException
{
int temp = 0;
ArrayList<String> ArrayList1 = new ArrayList<String>();
ArrayList<String> ArrayList2 = new ArrayList<String>();
ArrayList<String> ArrayList3 = new ArrayList<String>();
try
{
Scanner File1 = new Scanner(new File("/Users/Home/Desktop/File1.txt"));
while (File1.hasNext())
{
ArrayList1.add(File1.next());
}
Scanner File2 = new Scanner(new File("/Users/Home/Desktop/File2.txt"));
while (File2.hasNextLine())
{
ArrayList2.add(File2.next());
}
}
catch (FileNotFoundException ex)
{
ex.printStackTrace();
}
for (String ArrayList : ArrayList1)
{
System.out.println("File 1: " + ArrayList1);
}
for (String ArrayList : ArrayList2)
{
System.out.println("File 2: " + ArrayList2);
}
if(ArrayList1.size()>ArrayList2.size())
{
for(int i=0; i<ArrayList1.size()-1; i++)
{
if(ArrayList1.get(i).equals(ArrayList2.get(i)))
{
temp++;
}
}
}
if(ArrayList2.size()>ArrayList1.size())
{
for(int i=0; i<ArrayList2.size()-1; i++)
{
if(ArrayList2.get(i).equals(ArrayList1.get(i)))
{
temp++;
}
}
}
if(temp == 0)
System.out.println("The files are the same.");
else
System.out.println("There are " + temp + " differences between the files");
}
}

This is the problem:
if(ArrayList1.size()>ArrayList2.size())
{
//ArrayList1 is bigger!!!!
for(int i=0; i<ArrayList1.size()-1; i++)
{
if(ArrayList1.get(i).equals(ArrayList2.get(i)))
// ArrayList2 does not contain as many elements as ArrayList1
{
temp++;
}
}
}
therefore. You can have your loop from 0 -> ArrayList.size() but be sure to use the shorter list as the limit for the loop! :-)

Alternatively, you can replace:
for(int i=0; i<ArrayList1.size()-1; i++)
With:
for (String s : ArrayList1)
This is called a for-each loop and can be used for more readable simpler iteration.

As Sara Seppola already mentioned, you need to use the smallest of the two sizes to compare the elements in the two lists. Currently, you're using the biggest of the two, which guarantees that you'll go out of bounds on the smaller list.
Also, you should be using ArrayList1.size() and not ArrayList1.size()-1 in your loop limits, as the strictly less than check in your loop condition currently causes i to iterate from 0 to ArrayList1.size()-2 - which is one too short. Again, the index-out-of-bounds is not caused by the -1, but rather because of the incorrect size used in the condition.
Finally, you're not accounting for the case where the lists have equal sizes. Currently, your code gives "The files are the same" since there's not if-test which passes when ArrayList1.size() == ArrayList2.size().
if(ArrayList1.size() >= ArrayList2.size())
{
// Here, ArrayList1.size() >= ArrayList2.size()
// Use the smallest size as limit so we stay in bounds for both
// In this case, that's ArrayList2.size()
// When the lists have equal length, both sizes could be used
// as limit so it doesn't really matter whether you use
// > or >= in the test of the above if-statement
for(int i=0; i<ArrayList2.size(); i++)
{
if(ArrayList1.get(i).equals(ArrayList2.get(i)))
{
temp++;
}
}
}
else
{
// Here, ArrayList1.size() < ArrayList2.size()
// so use ArrayList1.size() as the limit
for(int i=0; i<ArrayList2.size(); i++)
{
if(ArrayList2.get(i).equals(ArrayList1.get(i)))
{
temp++;
}
}
}
There's still an error in your code though: you're only comparing corresponding elements. What about the extra elements from the larger list? Those should be counted as differences as well.
A quick fix would be to simply subtract the two sizes to get the number of extra elements in the bigger list, and use that as initial value for the number of difference:
if(ArrayList1.size() >= ArrayList2.size())
{
temp = ArrayList1.size() - ArrayList2.size();
// [for loop]
}
else
{
temp = ArrayList2.size() - ArrayList1.size();
// [for loop]
}
Of course, you could still simplify your code. You could use Math.min(ArrayList1.size(), ArrayList2.size()) to get the smallest of the two sizes and remove the duplicated loop. You could also use Math.abs(ArrayList1.size() - ArrayList2.size()) to get the number of extra elements, regardless whether ArrayList1 or ArrayList2 is the largest. I'll leave that as an exercise for the reader. ;-)

if(ArrayList1.size()>ArrayList2.size())
{
for(int i=0; i<ArrayList1.size()-1; i++)
{
if(ArrayList1.get(i).equals(ArrayList2.get(i)))
{
temp++;
}
}
}
Here you first check if ArrayList1 has more items than ArrayList2, and then you loop over the bigger ArrayList1, using get(i) on ArrayList1 as well as ArrayList2.
Because ArrayList1 has more items than ArrayList2, eventually you will get an item from at index X from ArrayList1 that you cannot get from ArrayList2 because ArrayList2 contains less items.
Example: ArrayList1 has 10 items and ArrayList2 has 9 items. You enter the if because 10 > 9. Then at the last iteration in the for loop you do ArrayList1.get(9) which is fine because it has 10 items and this gets the 10th, but ArrayList2.get(9) will fail because it has only 9 items. 8 is the highest index you can work with.
The second if has the same problem, but the other way around.
A fix to stop the error from occurring would be to
for(int i = 0; i < ArrayList2.size(); i++)
{
...
This might not do what you want your code to do, but the error will be gone.

Related

Why does my program not count every duplicate number in a certain list, but works for all others

I'm trying to count the number of duplicate integers in an ArrayList created from a file of roughly 20_000 values, each separated by a newline character. My current code works for every list except for a specific list that I cannot change easily and am stuck with.
//Arrays Class, use numerical sorting method
//Read in each number and look for duplicates, return the number of duplicates.
System.out.println("Creating List.....");
File numbers = new File("src/testlist");
List<Integer> numberlist = new ArrayList<Integer>();
try {
Scanner input = new Scanner(numbers);
while(input.hasNextInt()){
//int number = input.nextInt();
numberlist.add(input.nextInt());
//System.out.println(number);
}
System.out.println("List Created");
input.close();
}catch(FileNotFoundException e) {
e.printStackTrace();
}catch(NoSuchElementException r){
r.printStackTrace();
System.out.println("oops");
}
System.out.println("Sorting Numerically.....");
Collections.sort(numberlist);
System.out.println(numberlist);
System.out.println("Counting Duplicate Numbers.....");
int duplicates = 0;
for(int i = 0; i < numberlist.size()-1; i++){
if(numberlist.get(i) == numberlist.get(i+1)){
duplicates++;
numberlist.remove(i);
}
}
System.out.println("Duplicates: " + duplicates);
The file im using is here.
I've tried other handmade test data to prove that this program works as intended, but this specific list is giving me a problem.
Ass i mentioned in the comment, remove
numberList.remove(i)
and your loop will work as aspected
Easiest way to count duplicates as you need, is Casting the list to an Set and comparing the size of both. In a Set all values are unique.
Set<Integer> set = new HashSet<Integer>(numberList);
System.out.println( numberList.size() - set.size() );
When you do
numberList.remove(i)
the for cycle skips one element. Indeed, you remove element number i, and the next evaluation should continue from number i, and not i+1.
Indexes get weird things if you change the list elements while iterating, and it's never a good practice to do such things.
The cleanest way to perform this is to keep the source list without removing anything, and copying the elements into a new list, skipping duplicates.
In this way you'll have a new list, with the result (the list without duplicates) and their number is easily calculated from this list's size.
public static void countDuplicates() {
Integer count = 0;
List<Integer> list = getNumbersFromFile();
Set<Integer> unique = new HashSet<Integer>(list);
for (Integer key : unique) {
if (Collections.frequency(list, key) > 1) {
count++;
}
}
System.out.println("Count Of Duplicates " + count);
}
public static List<Integer> getNumbersFromFile() {
File numbers = new File("src/numbers.txt");
List<Integer> numberlist = new ArrayList<Integer>();
try {
Scanner input = new Scanner(numbers);
while (input.hasNextInt()) {
// int number = input.nextInt();
numberlist.add(input.nextInt());
// System.out.println(number);
}
System.out.println("List Created");
input.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (NoSuchElementException r) {
r.printStackTrace();
System.out.println("oops");
}
return numberlist;
}

IndexOutOfBoundsException in ArrayList Java

Whenever I try to run the code I get IndexOutOfBoundsException. I have tried numerous of ways fixing it but none of them have helped. The method should add a new String element "****" into ArrayList before every String which's length is equal to 4. In this case, it must add "****" before "5555".
Where could be the problem?
import java.util.ArrayList;
public class Main {
public static ArrayList<String> markLength4(ArrayList<String> list) {
int sum = 0;
for ( int i = 0; i < list.size(); i++) {
if (list.get(i).length() == 4) {
list.add(list.indexOf(i), "****");
}
}
return list;
}
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("ddddddddddddd");
list.add("fffffffffffff");
list.add("5555fdgdfg");
list.add("5555");
list.add("5555");
System.out.println(markLength4(list));
}
}
list.indexOf(i) will return -1, since i doesn't appear in your list. Therefore adding an element at the -1 position will throw an exception.
If you change list.add(list.indexOf(i), "****") to list.add(i, "****");, you'll get an infinite loop that will end with OutOfMemoryError, since the newly added String also has a length() of 4, so another String will be added on the next iteration, and so on.
i is not in your arraylist - it is a list of String, not Integer. That means that list.indexOf(i) == -1.
From your description, I think you mean:
list.add(i, "****");
but you will also need to increment i, e.g.
list.add(i++, "****");
to avoid the infinite loop that Eran mentions.
Or, of course, you can iterate the list backwards, and avoid the infinite loop/need to change the loop variable inside the loop body:
for ( int i = list.size() - 1; i >= 0; i--)
{
if (list.get(i).length() == 4)
{
list.add(i, "****");
}
}
import java.util.ArrayList;
public class Test {
public static ArrayList<String> markLength4(ArrayList<String> list) {
int sum = 0;
for (int i = 0; i < list.size(); i++) {
if (list.get(i).length() == 4) {
list.add(i++, "****");
}
}
return list;
}
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("ddddddddddddd");
list.add("fffffffffffff");
list.add("5555fdgdfg");
list.add("5555");
list.add("5555");
list = markLength4(list);
for (String x : list) {
System.out.println(x);
}
}
}
You'll loop forever this way, because there's 4-lengthened strings forward and you keep adding...
You can solve this by looping from the end, but you'll have to be careful with your index(you should add and increment the index to avoid that)
After Editing list.add(i++,"****"); the code should work just fine.
Notable
If you want to add before use i++;.
If you want to add after your match use ++i;.
list.indexOf(i) is not present in the list . It will produce -1
-1 is not available in ArrayList
Replace the Line
list.add(list.indexOf(i), "****");
with the following line
list.set(i, "****");
It replace the existing content of the List with new element in the index of i with new element i.e (****)
list.indexOf(i) where i is an int and therefore not in your list will throw your error as stated in comments (index -1).
use either of the following:
list.add("str") to add a String to the end of the list
OR
list.set(i, "****") which will set the value at a given index to this new string.
In the markLength4 method, by adding the element in the for loop you keep adding Strings and increasing the list size. You need a flag that tells the index and then ends the loop. You can try something like that
public static ArrayList<String> markLength4(ArrayList<String> list) {
int i = 0;
boolean found = false;
int pos = 0;
while(i < list.size() && !found){
if (list.get(i).length() == 4) {
found = true;
pos = i;
}
i++;
}
list.add(pos, "****");
return list;
}

Sorting Strings as inserted into array in Java

I'm trying to create a program that takes user input and sorts it alphabetically as it comes in using compareTo String operations (not array.sort) and prints the final sorted array at the end. I've got most of the body of this problem down but am lost once I get to the sort function. Does anyone have any ideas on how I might be able to finish out the SortInsert method?
import java.util.*;
public class SortAsInserted {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int array_size = GetArraySize();
String[] myArray = new String[array_size];
for (int i = 0; i < array_size; i++){
String nextString = GetNextString();
String[] sortedArray = SortInsert(nextString, myArray);
}
PrintArray(sortedArray);
}
input.close();
}
}
public static String[] SortInsert(String nextString, String[] myArray){
for(int i = 0; i < myArray.length;)
if (nextString.compareToIgnoreCase(myArray[i]) > 0) {
i++;
//if current text is less(alphabetically) than position in Array
}else if (nextString.compareToIgnoreCase(myArray[i]) < 0){
}
}
public static int GetArraySize(){
Scanner input = new Scanner(System.in);
System.out.print("How many items are you entering?: ");
int items_in_array = input.nextInt();
return items_in_array;
}
public static void PrintArray(String[] x) {
for (int i = 0; i < x.length; i++){
System.out.print(x[i]);
}
}
public static String GetNextString(){
Scanner input = new Scanner(System.in);
System.out.println("Enter the next string: ");
String next_string = input.nextLine();
return next_string;
}
}
There are a number of problems with this code. First I'll answer your immediate question, then enumerate some of the other problems.
The SortInsert method takes a String[] that will have been initialized with null values, so you will need to take that into account. The for loop would look something like this. (I'm using comments instead of writing the actual code since I'm not doing the project)
for (int i=0; i<myArray.length; ++i) {
if (myArray[i] == null) {
// we found a blank spot. use it to hold nextString.
break;
} else if (nexString.compareToIgnoreCase(myArray[i]) < 0) {
// nextString should be in spot i, so make room for it
// by shuffling along whatever is in the array at "i" and later
// by one place, then put nextString into position "i"
break;
}
// otherwise we'll just move to the next position to check
}
Now for the other issues.
You have a Scanner object in main that is never used. There's no point in having it and closing it at the end if your other methods make their own.
myArray will always be the sorted array so there's no point in making a local variable called sortedArray and return it from SortInsert. Note that your attempt to print sortedArray would fail anyway because that local variable is only in scope within the for loop.
When printing it should be myArray being passed to PrintArray.
If you're going to sort as you go, the TreeMap data structure is what you should be using, not an array. However, if you want to sort as you go with an array, you need to add some lines into your else if clause in SortInsert (should be sortInsert, BTW). (Another question: why is it else if rather than just else?)
The lines should create a new array of size one greater than the existing array, copy the first i-1 elements of the old array to the new array, put the new element in position i, then copy the remaining elements of the old array into positions one greater in the new array.
Once you find the position you wish to insert at, you have to shift all of the following elements down by one. Something like the following:
String temp = array[position];
for (int j = position+1; j < array_size-1; j++) {
String temp2 = array[j];
array[j] = temp;
temp = temp2;
}
array[array_size-1] = temp;

Skipping a particular value of ArrayList during printing

My Code is as follows:
ArrayList<Integer> al = new ArrayList();
al.add(1);
al.add(2);
al.add(3);
al.add(3);
al.add(4);
I want the following pattern during printing:
[1,2,4]
I tried both for loop and Iterator but I am not getting the desired output.
Help me to sort out!
I found the solution and that is
for(int i=0;i<al.size();i++) {
if(al.get(i)!=3)
System.out.println(al.get(i));
}
thanks for your help
Now I want to get the same output, not through printing but by deleting elements of ArrayList, I tried with the same condition but I got exception
and the answer is
Iterator<Integer> iter = al.iterator();
while (iter.hasNext()) {
if (iter.next().intValue() == 3) {
iter.remove();
}
}
System.out.println(al);
Step through all the items in the ArrayList and test if they are equal to 3, if they are not, print them.
for (Integer i : al) //for each Integer in the al list
{
if (!i.equals(3)) //if it is NOT (!) equal to 3
{
System.out.println(i); //then print it
}
}
Obviously if you want to skip more than just the number 3 you will need to expand the condition the if uses.
Note on removing elements from the list
If you try and remove from the list within the loop using this method you will encounter problems with ConcurrentAccessException, this is dealt with in this question.
If you want to get the list element and as per your output it seems you want to print 1 and even numbers in the list
for(int i=0; i< a1.size(); i++) //iterate over List
{
if(a1.get(i)%2=0 || a1.get(i) == 1) //print if 1 or even
System.out.println(a1.get(i));
}
You can also use the forEach method (Java 8):
al.forEach(v -> {if(v!=3) System.out.println(v);});
add the required skipping values in a list and check against that list before printing
My code:run and give comment(views please)
import java.util.*;
public class Mycode{
public static void main(String []args){
ArrayList<Integer> al = new ArrayList();
al.add(1);
al.add(2);
al.add(3);
al.add(3);
al.add(4);
ArrayList<Integer> al1 = new ArrayList();
al1.add(3);
al1.add(2);
int flag=0;
for(int j=0; j< al.size(); j++)
{
flag=0;
for(int i=0; i< al1.size(); i++)
{
if(al.get(j)==al1.get(i))
flag=1;
}
if(flag==0)
System.out.println(al.get(j));
}
}
}

Iterating through a variable length array

How do I iterate over a Java array of variable length.
I guess I would setup a while loop, but how would I detect that I have reached the end of the array.
I guess I want something like this [just need to figure out how to represent myArray.notEndofArray()]
index = 0;
while(myArray.notEndofArray()){
system.out.println(myArray(index));
index++;
}
for(int i = 0; i < array.length; i++)
{
System.out.println(array[i]);
}
or
for(String value : array)
{
System.out.println(value);
}
The second version is a "for-each" loop and it works with arrays and Collections. Most loops can be done with the for-each loop because you probably don't care about the actual index. If you do care about the actual index us the first version.
Just for completeness you can do the while loop this way:
int index = 0;
while(index < myArray.length)
{
final String value;
value = myArray[index];
System.out.println(value);
index++;
}
But you should use a for loop instead of a while loop when you know the size (and even with a variable length array you know the size... it is just different each time).
Arrays have an implicit member variable holding the length:
for(int i=0; i<myArray.length; i++) {
System.out.println(myArray[i]);
}
Alternatively if using >=java5, use a for each loop:
for(Object o : myArray) {
System.out.println(o);
}
You've specifically mentioned a "variable-length array" in your question, so neither of the existing two answers (as I write this) are quite right.
Java doesn't have any concept of a "variable-length array", but it does have Collections, which serve in this capacity. Any collection (technically any "Iterable", a supertype of Collections) can be looped over as simply as this:
Collection<Thing> things = ...;
for (Thing t : things) {
System.out.println(t);
}
EDIT: it's possible I misunderstood what he meant by 'variable-length'. He might have just meant it's a fixed length but not every instance is the same fixed length. In which case the existing answers would be fine. I'm not sure what was meant.
here is an example, where the length of the array is changed during execution of the loop
import java.util.ArrayList;
public class VariableArrayLengthLoop {
public static void main(String[] args) {
//create new ArrayList
ArrayList<String> aListFruits = new ArrayList<String>();
//add objects to ArrayList
aListFruits.add("Apple");
aListFruits.add("Banana");
aListFruits.add("Orange");
aListFruits.add("Strawberry");
//iterate ArrayList using for loop
for(int i = 0; i < aListFruits.size(); i++){
System.out.println( aListFruits.get(i) + " i = "+i );
if ( i == 2 ) {
aListFruits.add("Pineapple");
System.out.println( "added now a Fruit to the List ");
}
}
}
}

Categories