5

We are given a list of words in the form of an ArrayList as follows:

 public ArrayList<String> getListOfStrings(){
     ArrayList<String> list = new ArrayList<String>();
     list.add("This");
     list.add("is");
     list.add("an");
     list.add("exercise");
     list.add("to");
     list.add("illustrate");
     list.add("the");
     list.add("use");        
     list.add("of");
     list.add("ArrayLists");        
     list.add(".");
     return list;
    }

How do I write a method that removes all words in that list (i.e. all the objects in the ArrayList) that have the length "len" entered by the user?

I already wrote a method that lists all the words of length "len" entered by the user, and it works, it's as follows:

public ArrayList<String>getWordsWithLength(int len, ArrayList<String> lijst){
    ArrayList<String> list = new ArrayList<String>();
    for(String woord: lijst){
        if(woord.length()==len){
            list.add(woord);
        }
    }
    return(list);

}

But as a beginner in java, I'm stuck on how to remove the words of length "len". Please help! (I am under the impression that you start by removing them from the end of the list, back-to-front as it were)

user2895102
  • 59
  • 1
  • 4
  • You _remove_ them by not adding them to the new list you return. – Sotirios Delimanolis Oct 18 '13 at 14:13
  • 1
    Backwards would also work, but only with a traditional `for` loop (of the `for(int i=list.size-1;i>=0;i--)` variety. AbstractChaos's solution is prefered however – Richard Tingle Oct 18 '13 at 14:18
  • Thanks, could you elaborate on this? I'm getting an error: "size has private access in java.util.ArrayList" Not to mention I don't 100% follow what's going on in this code (again I'm a beginner) – user2895102 Oct 18 '13 at 14:50
  • @user2895102 - That was a typo on Richard's part. It should be `list.size()` not `list.size`. All it does is loop through the indices backwards, which ensures the indices don't get screwed up as you're removing elements. – DaoWen Oct 18 '13 at 18:27

6 Answers6

7

The way your currently iterating through the list wont allow you to remove it with an exception but an iterator would.

Iterator<String> it = list.iterator();
while(it.hasNext()) {
 if([Condition]) {
   it.remove();
  }
}
AbstractChaos
  • 4,153
  • 1
  • 16
  • 28
  • 1
    You are correct, but the assignment specifies to use a simple "for" loop as specified by Richard Tingle up above: "Backwards would also work, but only with a traditional for loop (of the for(int i=list.size-1;i>=0;i--) variety. AbstractChaos's solution is prefered however – " – user2895102 Oct 18 '13 at 14:43
  • 1
    @user2895102 - You can translate the loop above into a for loop as well: `for (Iterator it = list.iterator(); it.hasNext();) ...` – DaoWen Oct 18 '13 at 18:26
4

Your method can already serve as a removal, just change the == to a !=

public ArrayList<String> getStringsWithoutEqualLength(int len, ArrayList<String> lijst){
    ArrayList<String> list = new ArrayList<String>();
    for(String woord: lijst){
        if(woord.length() != len){ 
            list.add(woord);
        }
    }
    return(list);
}

If what you are attempting to do is remove the elements from lijst, then just reassign the returned list to it.

ArrayList<String> yourList = ...;
yourList = instance.getStringsWithoutEqualLength(someLength, yourList);

You have effectively removed the longer elements and done it faster than if you had used an Iterator. Every time you remove with an Iterator, you have to resize your backing array.

Sotirios Delimanolis
  • 252,278
  • 54
  • 635
  • 683
  • Is this actually faster than using an `Iterator`? I would have pegged them at about the same speed. The `Iterator` should be able to do removals in constant time right? Or is that only for linked lists? – Cruncher Oct 18 '13 at 14:28
  • @Cruncher That would be for `LinkedList`. The `ArrayList$Itr` calls `ArrayList#remove()` which does a `System.arraycopy` for the underlying array. – Sotirios Delimanolis Oct 18 '13 at 14:29
  • @SotiriosDelimanolis but isn't that effectively what you are doing? Copying the ArrayList minus one would be similar to System.arraycopy except that you also instantiate a Deeper hierarchy of classes? – AbstractChaos Oct 18 '13 at 14:31
  • @AbstractChaos In this we are copying the array only once. Otherwise you would have to copy it for every removal. – Cruncher Oct 18 '13 at 14:32
  • 2
    @AbstractChaos Yeah, depends on the amount of removals. But if we are analyzing Big-O, this is faster. – Sotirios Delimanolis Oct 18 '13 at 14:34
  • @SotiriosDelimanolis I think the `Iterator` example is more java-esque(I wish there was a name as cool as "pythonic") though. The idea is to use the right List implementation depending on how the data is used. If you only ever iterate and don't use random access, then you gain nothing by using an `ArrayList`. – Cruncher Oct 18 '13 at 14:40
  • @Cruncher Use the interfaces to your advantage. Use computer science to your advantage as well :) – Sotirios Delimanolis Oct 18 '13 at 14:44
1

You have to remove values from a List by using an Iterator to prevent a ConcurrentModificationException.

List<String> myList = getListOfStrings();
Iterator<String> it = myList.iterator();
while (it.hasNext()) {
   if(it.next().length() == 3){
    it.remove();
   }
}
Jeroen Vannevel
  • 41,258
  • 21
  • 92
  • 157
0

You can even use the same method by adding a boolean parameter.

public ArrayList<String>getWordsWithLength(int len, ArrayList<String> lijst, boolean complement){
    ArrayList<String> list = new ArrayList<String>();
    for(String woord: lijst){
        if((woord.length()==len) != complement){
            list.add(woord);
        }
    }
    return(list);

}

If you pass in complement as true, if will give you everything with that doesn't have length == len. complement as false will behave as usual.

Cruncher
  • 7,241
  • 1
  • 26
  • 62
0

While I think that @SotiriosDelimanolis's answer is probably what you should use, I also wanted to point out that with Java 8 you can easily do this using a Stream and a Predicate to filter on:

 List<String> list2 = list.stream()
                      .filter(s -> s.length() != 3)
                      .collect(Collectors.toList());

Here's a full test class:

import java.util.*;
import java.util.stream.*;

class Test {
  public static void main(String args[]) {
     ArrayList<String> list = new ArrayList<String>();
     list.add("This");
     list.add("is");
     list.add("an");
     list.add("exercise");
     list.add("to");
     list.add("illustrate");
     list.add("the");
     list.add("use");
     list.add("of");
     list.add("ArrayLists");
     list.add(".");
     System.out.println(list);
     List<String> list2 = list.stream()
                          .filter(s -> s.length() != 3)
                          .collect(Collectors.toList());
     System.out.println(list2);
  }
}

and my test output:

$ java Test
[This, is, an, exercise, to, illustrate, the, use, of, ArrayLists, .]
[This, is, an, exercise, to, illustrate, of, ArrayLists, .]
DaoWen
  • 31,184
  • 6
  • 65
  • 95
0

in Scala you'd just do

list.filter(_.length != len)
fommil
  • 5,370
  • 5
  • 33
  • 74
  • In [Clojure](http://clojure.org/) you'd just do `(remove #(= (count %) len) my-list)`—but the OP didn't ask about Scala or Clojure. However, Java 8 _does_ add a Scala-esque `stream` package, which is what I used in my answer. Too bad we won't be able to expect people to actually _have_ Java 8 for another year or two... – DaoWen Oct 18 '13 at 15:37