我有以下代码 -
import java.util.ArrayList;
public class ArrayListExp{
public static void main (String[] args){
ArrayList<String> name = new ArrayList<String>();
name.add("Chris");
name.add("Lois");
name.add("Meg");
name.add("Meg");
name.add("Brain");
name.add("Peter");
name.add("Stewie");
System.out.println(name);
for ( int i = 0; i < name.size(); i++){
String oldName = name.get(i);
if(oldName.equals("Meg"))
{
name.remove(i);
}
}
System.out.println(name);
}
}
但是这里它给了我输出 -
[Chris, Lois, Meg, Meg, Brain, Peter, Stewie]
[Chris, Lois, Meg, Brain, Peter, Stewie]
我没有明白这一点,为什么这不是删除Meg
但是我只尝试了一个Meg
,在这种情况下它正在运行。而当我在最后添加更多Meg
时,Meg
中的ArrayList
未从{{1}}中删除。为什么呢?
答案 0 :(得分:23)
删除第一个“Meg”时,索引i=2
。然后它会递增,但由于其中一个“Meg”已被删除,现在name.get(3)
是“Brain”。所以你实际上没有检查第二个“Meg”。
解决问题。您可以在删除元素时递减索引:
public class ArrayListExp{
public static void main (String[] args){
ArrayList<String> name = new ArrayList<String>();
name.add("Chris");
name.add("Lois");
name.add("Meg");
name.add("Meg");
name.add("Brain");
name.add("Peter");
name.add("Stewie");
System.out.println(name);
for ( int i = 0; i < name.size(); i++){
String oldName = name.get(i);
if(oldName.equals("Meg"))
{
name.remove(i);
i--;
}
}
System.out.println(name);
}
}
答案 1 :(得分:5)
您正在迭代第一个Meg
,当删除Meg
时,数组值会移一。
[Chris, Lois, Meg, Meg, Brain, Peter, Stewie]
0 1 2 3 4 5 6
第一个Meg
被删除,并且循环递增i因为它完成了for循环中的所有内容的执行,因此i
现在将为3并且数组已被修改:
[Chris, Lois, Meg, Brain, Peter, Stewie]
0 1 2 3 4 5
尝试向后迭代。
for ( int i = name.size() - 1; i >= 0; i--){
String oldName = name.get(i);
if(oldName.equals("Meg"))
{
name.remove(i);
}
}
答案 2 :(得分:4)
您可以使用name.removeAll(Arrays.asList("Meg"));
删除所有"Meg"
您的完整代码将是
for ( int i = 0; i < name.size(); i++){
String oldName = name.get(i);
if(oldName.equals("Meg"))
{
name.removeAll(Arrays.asList("Meg"));
}
}
答案 3 :(得分:1)
你在从0到N迭代时从ArrayList中移除,所以当你在索引N处移除第一个Meg时,下一个Meg向下移动到索引N,然后你将i递增到N + 1。所以第二梅格不会被删除。尝试以相反的顺序迭代(N到0):
for ( int i = name.size() - 1; i >= 0; i--) {
答案 4 :(得分:1)
因为当i = 2且条件为真时,删除meg并且所有索引都向上移动。因此下一个我会指向Brain,而不是meg。
试试这个。 (如果条件成立,则将i减1)
for ( int i = 0; i < name.size(); i++){
String oldName = name.get(i);
if(oldName.equals("Meg"))
{
name.remove(i);
i--;
}
}
答案 5 :(得分:0)
删除元素时不应使用for循环。在实现某些逻辑时总会出现问题。为您的问题使用反向循环,并始终尝试使用每个。
答案 6 :(得分:0)
Collection
接口现在提供了一种removeIf
方法,该方法可以对其进行适当的修改,如果要删除该元素,您可以提供一个返回true
的谓词。
因此,您可以像这样使用lambda:
name.removeIf(name -> name.equals("Meg"));
也可以使用方法参考以使其更加简洁。如果有null
个元素,以下代码也将起作用。
name.removeIf("Meg"::equals);
如果您不想修改旧列表,则可以使用Stream
和filter
通过排除条件来获取应保留的所有项目的List
。 / p>
final List<String> filtered = name.stream()
.filter(name -> !"Meg".equals(name))
.collect(Collectors.toList());
如果您特别需要ArrayList
,请使用Collectors.toCollection
和构造函数引用代替。
final ArrayList<String> filtered = name.stream()
.filter(name -> !"Meg".equals(name))
.collect(Collectors.toCollection(ArrayList::new));
问题是ArrayList在迭代时被修改,这会改变其大小并向前移动后面的元素;如果有连续的元素需要删除,这是一个问题。每次删除元素时,都需要将索引减少一,因为该索引现在将引用下一个元素。
for (int i = 0; i < name.size(); i++) {
String oldName = name.get(i);
if (oldName.equals("Meg")) {
name.remove(i);
i--;//Important!
}
}
for (int i = name.size() - 1; i >= 0; i--) {
String oldName = name.get(i);
if (oldName.equals("Meg")) {
name.remove(i);
}
}
通常,使用Iterator
最适合这种操作,因为它支持在通过调用Iterator#remove
进行迭代的同时删除元素。这也会修改List
到位。对于更复杂的操作,请考虑使用ListIterator
。
final Iterator<String> it = name.iterator();
while(it.hasNext()){
final String name = it.next();
if(name.equals("Meg")){
it.remove();
}
}