在从文件中读取和删除某些行时遇到问题?
该计划的目的是从文本文件中删除某些运动队及其成员,然后用新的值集覆盖原始文件。 这是通过将值读入数组,然后循环遍历数组并删除团队名称和接下来的2行来尝试的,但由于某种原因,它会在索引之后停止通过数组。
我被卡住了,所以任何帮助都会很棒
码:
private void RemoveSportsTeamButtonActionPerformed(java.awt.event.ActionEvent evt) { String ChosenTeam = ""; ChosenTeam = JOptionPane.showInputDialog("What Team Do you want to remove?"); ArrayList Teamlist = new ArrayList(); if (ChosenTeam.length() > 0) { } else { Scanner Reader = null; try { Reader = new Scanner(new File("ListofSportTeams.txt")); } catch (FileNotFoundException ex) { } while (Reader.hasNext()) { Teamlist.add(Reader.next()); } Reader.close(); for (int count = 0; count < Teamlist.size(); count++) { { if (Teamlist.get(count).equals(ChosenTeam)) { Teamlist.remove(count); Teamlist.remove(count + 1); Teamlist.remove(count + 2); } } } } }
SportTeamList.txt =
Team1 Jeff James Team2 Steve Peter
迭代时不应该从List
remove
。 你在做什么
考虑一个简单的例子,我有一个列表{1,2,3,4,5}
。 让我们假设其0索引,我想删除大于3的所有数字。
0 – 列表项为1
,保留
1 – 列表项是2
,保持
2 – 列表项是3
,删除。 所有元素都被移位,列表现在是{1,2,4,5}
。
3 – 列表项是5
,删除
4 – 列表项是oops,不再是4
所以我超过了List
的结尾,因为当我开始迭代时我将大小设置为5
,但是在我删除索引2
处的元素后它变为4
,当我在索引3
处删除元素时它变为3
。
你可能会说,“啊哈,我可以通过while
循环解决这个问题”:
int i = 1; while(i < teams.size()) { //do stuff }
但这更糟糕的是 :
0 - 列表项为1
,保留
1 - 列表项是2
,保持
2 - 列表项是3
,删除。 所有元素都被移位,列表现在是{1,2,4,5}
。
3 - 列表项是5
,删除
所以,没有错误。 看起来问题已修复。 但是这个清单包含什么? 它包含{1,2,4}
。 但是4
大于3
。 由于指数转移,它被跳过了。 你现在有一个更阴险的错误。
如果您正在使用适当的增强型foreach循环,请执行以下操作:
for(final String team : teams) { //do stuff with team }
你可以正确地得到一个ConcurrentModificationException
。 这只是使用增强型foreach循环而不是索引循环的众多原因之一。
为了做你想做的事,请使用Iterator
:
final Iterator iter = teams.iterator(); while(iter.hasNext()) { if(iter.next().equals(testString)) iter.remove(); }
我将重申我的评论:
请始终使用Java命名约定 。 变量应始终在camelCase
。 PascalCase
是为类保留的。
UPDATE
可能更容易,因此使用indexOf
方法在List
查找团队名称并删除所需的元素
public void remove(final List teams, final String name) { final int idx = teams.indexOf(name); if(idx < 0) throw new IllegalArgumentException("Team " + name + " not present in list."); for(int i = idx + 2; i >= idx; --i) teams.remove(i); }
反向删除项目非常重要 。 这是由于与上述相同的问题,如果您删除索引处的项目(例如) 10
那么索引11
处的项目将向下移动。 因此,当您去索引11
处的项目时,您实际上正在删除最初为索引12
。
你可以使用肮脏的技巧
for(int i = 0; i < 2; ++i) teams.remove(idx)
即继续删除找到的索引处的项目,因为列表将向下移动以填补您将实际删除所需项目和其上方的两个项目的差距。 我认为这使得代码很难阅读。 您可能会忘记这个技巧然后回到代码并且必须弄清楚它正在做什么。
现在,我使用两个列表。 一个是原始的,另一个是删除列表。 我阅读原始列表,如果条目以“团队”开头(如果您有其他逻辑用于区分团队名称和成员名称,请添加),我将其添加到删除列表以及以下条目,直到下一个团队名称找到了保留。 最后,我从原始列表中删除所有删除条目。
public class ListRemovalDemo { public static void main(String[] args) { List teamList = new ArrayList (); teamList.add("TeamName1"); teamList.add("Member1Team1"); teamList.add("Member2Team1"); teamList.add("TeamName2"); teamList.add("Member1Team2"); teamList.add("Member2Team2"); teamList.add("TeamName3"); teamList.add("Member1Team3"); teamList.add("Member2Team3"); List removalList = new ArrayList (); String teamToRemove = "TeamName2"; Iterator teamListIterator = teamList.listIterator(); String entry; while(teamListIterator.hasNext()) { entry = teamListIterator.next(); if(entry.equals(teamToRemove)) { removalList.add(entry); if(teamListIterator.hasNext()) { entry = teamListIterator.next(); while(!entry.startsWith("Team")) { removalList.add(entry); if(teamListIterator.hasNext()) entry = teamListIterator.next(); else break; } } } } teamList.removeAll(removalList); System.out.println("After removal of " + teamToRemove + ":\n" + teamList); } }
产量
After removal of TeamName2: [TeamName1, Member1Team1, Member2Team1, TeamName3, Member1Team3, Member2Team3]