Hacker News new | ask | show | jobs
by newgame 4024 days ago
What about iterating from the end of the list in this particular case. This way you don't need a temporary list

    for (int i = names.size()-1; i >= 0; i--) {
        String name = names.get(i);
        if (name.startsWith("B")) names.remove(i);
    }
Admittedly, needing to use an explicit index counter is not as nice (and more prone to errors) as using the other for syntax. But one could imagine a language with e.g. macros that made the backwards-looping syntax more intuitive (I assume a single-threaded situation and an ArrayList).

Your general point still stands though.

2 comments

Both implementations are incorrect as they needlessly mutate the input list:

  List<String> namesNotStartingWithB = new ArrayList<>();
  for (String name : names) {
      if (!name.startsWith("B")) {
          namesNotStartingWithB.add(name);
      }
  }
Imagine a scenario where you're filtering one of the arguments to a method: the input will be mutated with no indication to the caller (or in the method signature), causing bugs, iterator invalidation etc.
Good additional point that demands repetition: Don't mutate arguments to a (public) method if not absolutely necessary.

Just to be clear, that does not make the approaches "incorrect". The list "names" is not necessarily an argument to a method. It might be a local, intermediate result that does not have the risk of "mutation at a distance".

I know what you're trying to say, but the problem definition is to mutate the list, removing items that start with B.
How about:

  Iterator<String> it = names.iterator();
  while (it.hasNext())
  {
    if (it.next().startsWith("B"))
    {
      it.remove();
    }
  }
Yes, much better. For anyone interested, here's a link with background information: http://stackoverflow.com/questions/1196586/calling-remove-in...