IndexOutOfBoundsException while adding to a list in an arraylist - java

I am making a program which has to sort every English word based on the first two letters. Each group of two letters has it's own list which I have to add the words into therefore I have 676 lists in total. I tried making an ArrayList of Lists to do this:
public static List<List<String>> englishWordList = new ArrayList<List<String>>(673);
Now when I try to add elements to one of the lists I get this an IndexOutOfBoundsException
private static void letterSort(String s){
//Sorts the words by the first two letters and places in the appropriate list.
String letterGet = s.substring(0,2);
for(int i = 0; i < 676; i++){
if(letterGet.equals(letterCombos[i])){
Debug(s);
Debug(letterGet);
try{
englishWordList.get(i).add(s); \\IndexOutOfBoundsException here
}catch(Exception e){
e.printStackTrace();
System.exit(0);
}
}
}
Any help with fixing this would be very appreciated, also if any more information is needed I will be more than happy to add it.

You only initialized the englishWordList, but you didn't add anything to it. Therefore englishWordList is empty and any get(int) call will throw an IndexOutOfBoundsException.
You can fill it with empty Lists the following way (also note that you set initial capacity to 673 instead of 676):
public static List<List<String>> englishWordList = new ArrayList<List<String>>(676);
static {
for (int i = 0; i < 676; i++) {
englishWordList.add(new ArrayList<String>());
}
}

Related

Removing duplicates from an ArrayList?

Good afternoon everyone, I am currently studying for my Java Final and I have a review exercise that asks the reader to create a program that asks the user to input 10 integers and then to use a method to remove duplicates and display the distinct list. The method is provided for you as well.
I've gotten the majority of the code written, in fact I thought I was done until I realized that the for loop is removing more than just duplicates..
Here is my code:
public class lab25 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
int i;
//Create array list
ArrayList<Integer> numbers = new ArrayList<>();
System.out.println("Please enter 10 numbers!");
//Populate
for(i=0; i<10; i++) {
numbers.add(input.nextInt());
}
System.out.println("Your numbers are: " + numbers.toString());
removeDuplicate(numbers);
System.out.println("The distinct numbers are: " +numbers.toString());
input.close();
}
public static void removeDuplicate(ArrayList<Integer> list) {
int i;
for(i=0; i<list.size(); i++) {
if(list.contains(list.get(i))) {
list.remove(i);
}
}
}
}
Just curious what I have done wrong here? I think my issue might lie in my for loop.. Thanks to all who answer.
list.contains(list.get(i)) always returns true, since the i'th element of the List is contained in the List.
Therefore removeDuplicate is trying to remove all the elements (but you only remove half of them, since after removing the i'th element you skip the new i'th element).
There are many ways to remove duplicates. The most efficient involve using a HashSet. If you want to find duplicates using only List methods, you can check if list.lastIndexOf(list.get(i)) > i.
The expression list.contains(list.get(i)) is always true, since you're asking if the list contains some element from the list. You need to check if list.get(i) is contained in the first i-1 items in the list, which I recommend doing with a loop.
Be aware that a loop with list.remove will run slowly, since removing item i from an ArrayList is done by replacing item i with i+1, then replacing item i+1 with i+2 and so on. This means it takes around length^2 time to make a loop that calls remove in every iteration. The function list.contains has the same problem, as it has to go through the entire list. This may not matter if you have 10 items, but if you had a list with a million items, it would take a long time to run.
The easiest ways is to use Stream.distinct():
public static List<Integer> removeDuplicate(List<Integer> list) {
return list.stream().distinct().collect(Collectors.toList());
}
In case you are free to choose collection, you should use LinkedHashSet instead. It holds ordered unique numbers.
A solution could be this one. I startet at the end of the list that I don't delete indexes the loop has to visit in the future.
public static void removeDuplicate(ArrayList<Integer> list) {
int i = list.size() - 1;
while (i > -1) {
// check for duplicate
for (int j = 0; j < i; j++) {
if (list.get(i) == list.get(j)) {
// is duplicate: remove
list.remove(i);
break;
}
}
i--;
}
}
You are taking the list.get(i) which of course is present in the list, and you will delete all of the values in the end.
You could remove them by using a set:
Set<String> hs = new HashSet<>();
hs.addAll(numbers);
numbers.clear();
numbers.addAll(hs);
If you want to keep the current order and do not want to use set.
List<String> notduplicatedList =
new ArrayList<>(new LinkedHashSet<>(String));

compare two arraylist object not working

I have two array list with name list and sum from this kind of class :
public class Factor {
private String cat;
private String kind;
private String name;
private int number;
private String id;
}
my purpose is compare this two arraylist and if they have same object , list number = sum number else sum object add to list .
this is my try so far :
int size=list.size();
for (int j=0; j<size ;j++){
for (int i = 0; i < sum.size(); i++) {
if (list.get(j).getId().equals(sum.get(i).getId())){
list.get(i).setNumber(sum.get(i).getNumber());
} else {
list.add(new Factor(sum.get(i).getId(),sum.get(i).getCat(),sum.get(i).getKind(), sum.get(i).getName(), sum.get(i).getNumber()));
}
}
}
but problem is always two condition run any way it mean do below in if list.get(i).setNumber(sum.get(i).getNumber());
and after that do below in else
list.add(new Factor(sum.get(i).getId(),sum.get(i).getCat(), sum.get(i).getKind(),
sum.get(i).getName(), sum.get(i).getNumber()));
always add list ... so where am i wrong ?
Your logic was incorrect.
Based on the comments, you want to add to list all the elements of sum that don't have a matching ID in list. For that purpose you should iterate over the elements of sum first (i.e. in the outer loop).
int size=list.size();
for (int i = 0; i < sum.size(); i++) {
boolean found = false;
for (int j=0; j<size ;j++) {
if (list.get(j).getId().equals(sum.get(i).getId())) {
list.get(j).setNumber(sum.get(i).getNumber());
found = true;
break;
}
}
if (!found) {
list.add(new Factor(sum.get(i).getId(),sum.get(i).getCat(), sum.get(i).getKind(),
sum.get(i).getName(), sum.get(i).getNumber()));
}
}
you need to make sure both list size is the same, so if they are not the same size they wont be equal
Also this is a bad practice to compare two lists, a better way would be using a Set, just convert one of the lists to a set ( time complexity O(n) ) then loop over the other list and check if all elements are in the set you created from the other list, also you need to take care of duplicate case , so if duplicate is allowed in the list you need to use a map , where the id is the key and the value is the number of occurrences , while iterating over the other list if the key is found decrement the number and check if its not getting less than zero.
From your question, it's still not clear what you are trying to achieve from this code. Do you wanna compare every element of list array with every element of sum array or u just want to compare list array with the corresponding element of sum array.
As per my understanding,
From your code, I can see that u are using nested loos.
***for (int j=0; j<size ;j++)
{
for (int i = 0; i < sum.size(); i++) {}}***
So for every list(j) array, it will compare this all the elements of sum(i) array and out which some will execute IF block and some will execute else block depending upon the condition.
If this is not what u are looking for they give some more clarity on ur question.

Putting Strings in Lexicographic Order

This is my assignment, and I am not sure how to proceed. The output only prints my first four teachers, and I don't know why it isn't printing my last three teachers as well. Thanks!
Create an ArrayList called teachers. Fill the ArrayList with your teacher’s LAST NAMES ONLY in the order that you see them during the day (Period 1: Jensen, Period 2: Houge, Period 3: …, etc.) You only need to put the teacher’s last name in the ArrayList, so it would print [Jensen, Houge, etc…].) Print the ArrayList using a print method.
Write a method that takes your teachers ArrayList, and from it makes a new ArrayList called ordered, whererin your teacher’s names are now in lexicographic order. Print the resulting ArrayList. (DO NOT CHANGE YOUR ORIGINAL ARRAYLIST, MAKE A NEW ONE!)
import java.util.ArrayList;
public class LexicographicOrdering
{
public static void main (String [] args){
ArrayList<String> teachers = new ArrayList<String>();
teachers.add("Turnbow");
teachers.add("Dyvig");
teachers.add("Williams");
teachers.add("Houge");
teachers.add("Allaire");
teachers.add("Violette");
teachers.add("Dorgan");
System.out.println(teachers);
order(teachers);
}
public static void order(ArrayList<String> teachers ){
ArrayList<String> ordered = new ArrayList<String>();
for(int i = 0; i < teachers.size(); i++){
String str = teachers.get(i);
for(int j = 1; j < teachers.size(); j++){
if(str.compareTo(teachers.get(j)) > 0){
str = teachers.get(j);
}
}
ordered.add(str);
teachers.remove(str);
}
System.out.print(ordered);
}
}
So the issue here is with your static order method. As Karl suggests above, you want to break the method into two separate parts. The first will create an ArrayList named 'ordered' and then fill it with the data contained in the 'teachers' array.
ArrayList<String> ordered = new ArrayList(); //the second <String> is not required
for(int i = 0; i < teachers.size(); i++){
String str = teachers.get(i);
ordered.add(str);
}
The next objective is to sort the array in alphabetical order, which can be achieved using the Collections.sort(ArrayList) method which is contained in the java.util package.
Collections.sort(ordered);
And now you need to print the ArrayList.
System.out.println(ordered);
As this is a homework assignment, I would recommend reading up on the Collections.sort() method, along with an example of it. A quick google search pulled up the following website: http://beginnersbook.com/2013/12/how-to-sort-arraylist-in-java/
Also, I would recommend reading the API for the Collection class. https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#sort-java.util.List-
Edit:
At a quick glance, I would assume the reason that your string is cutting out the last 3 names is due to the fact that you are removing items from the list as you are looking at each position in the list. Essentially, you are looking at every other item in the list because of this.
So I figured it out! I only needed to set the first for loop back to zero. Here is the new code:
import java.util.ArrayList;
public class LexicographicOrdering
{
public static void main (String [] args){
ArrayList<String> teachers = new ArrayList<String>();
teachers.add("Turnbow");
teachers.add("Dyvig");
teachers.add("Williams");
teachers.add("Houge");
teachers.add("Allaire");
teachers.add("Violette");
teachers.add("Dorgan");
System.out.println(teachers);
order(teachers);
}
public static void order(ArrayList<String> teachers ){
ArrayList<String> ordered = new ArrayList<String>();
for(int i = 0; i < teachers.size(); i++){
String str = teachers.get(i);
for(int j = 1; j < teachers.size(); j++){
if(str.compareTo(teachers.get(j)) > 0){
str = teachers.get(j);
}
}
i =- 1;
ordered.add(str);
teachers.remove(str);
}
System.out.print(ordered);
}
}

Reusing input String[] with values from arrayList

I have the following code which sorts a mixed array of items while maintaining the position of types:
For example:
[20, "abc", "moose", 2,1] turns into [1, "abc", "moose", 2, 20]
Algorithm:
public class Algorithm {
public static String[] sortMixedArray(String[] input){
if (input.length == 0){
return input;
}
// make new arraylist for strings and numbers respectively
List<String> strs = new ArrayList<String>();
List<Integer> numbers = new ArrayList<Integer>();
// add values to the arraylist they belong to
for (String item : input){
if (NumberUtils.isNumber(item)){
numbers.add(Integer.valueOf(item));
} else {
strs.add(item);
}
}
// sort for O(nlogn)
Collections.sort(strs);
Collections.sort(numbers);
// reuse original array
for (int i = 0; i < input.length; i++){
if (NumberUtils.isNumber(input[i])) {
input[i] = String.valueOf(numbers.remove(0));
} else {
input[i] = strs.remove(0);
}
}
return input;
}
public static void main(String[] args) {
String[] test = new String[] {"moo", "boo"};
System.out.println(Arrays.toString(sortMixedArray(test)));
}
I have a two-part question:
1. Is switching between array and arraylist efficient? That is, should I have used arrays everywhere instead of arraylist if my input MUST be an array.
2. What is the best way to place arraylist items back into a array? I am checking for type, is there a better way?
1.If you do it the way you have it in your code then it's perfectly fine. If you know beforehand how many elements you will have it's better to use arrays but thats not the case in your example.
2.The best and easiest way is to use the toArray() function of the List interface.
ArrayList<String> list = ...;
String[] array = list.toArray(new String[list.size()]);
But this won't work for your code since you are merging two lists into one array. You can still improve your code a bit because you do not actually have to remove the items from the lists when putting them back in the array. This safes some computation since removing the first element from an ArrayList is very inefficient (O(N) runtime per remove operation).
for (int i = 0, s = 0, n = 0; i < input.length; i++) {
if (NumberUtils.isNumber(input[i])) {
input[i] = Integer.toString(numbers.get(n++));
} else {
input[i] = strs.get(s++);
}
}
No but it highly unlikely to matter unless you have a million of elements.
Do whatever you believe is simplest and most efficient for you, the developer.
BTW the least efficient operations is remove(0) which is O(N) so you might change that.

get value that occurs more than one in a list?

What are the the best methods to get values that occur more than once in a large list of words without slowing my run time?. My file contains 1xx,xxx words and I put them into a linked list. Now, I want to get only the words that occur more than once out of that list.
For example, if a list contains:
....This is is is just a test test....
I want to get is and test and put them into another list using an iterator.
I don't know if my code is right, and I think that this is not the best solution to approach for this problem.
for(int i = 0; i < word.size(); i++) {
Word s = word.get(i);
Word s1 = word.get(i+1);
if(s.equals(s1)) {
newWord.add(s);
}
}
Put them all into HashSet instead of list and check the return value of add() method.
HashSet<Word> wordSet = new HashSet<>();
for(int i = 0; i < word.size(); i++) {
if(!wordSet.add(word.get(i)){
//Found duplicate
}
}
Note that you can also do it during/instead of creation of the list of the words.
Build a hashmap with the word as key and it count as value.
for(each word in list)
{
count = 1;
if(map.contains(word))
{
count = map.get(word);
}
else
count = 1;
map.put(word,count);
}
Then iterate over the hashmap and check if values is 1, and add the word to your list.
If you can sort the list, then finding duplicates is quick and easy.

Categories