Поэтому мне нужно создать класс под названием mylistofstrings, который является именно тем, чем он звучит, массивом строк. Один из методов, который я должен написать, - это сохранить весь метод, который сохраняет только строки в списке, которые равны строке, введенной в качестве параметра. Кажется, что цикл for пропускает половину вещей, которые он должен удалить, любые идеи, почему? Метод размера просто возвращает количество элементов в списке и является простым для публикации.
public boolean retain(String string) {
if (string == null) {
throw new NullPointerException();
}
MyListOfStrings temp= new MyListOfStrings(this);
int t=this.size();
for (int i=0;i<this.size;i++){
if (string.equals(temp.get(i))!=true){
this.remove(i);
}
}
return t<this.size();
Здесь метод get:
public String get(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
return strings[index];
}
и метод удаления:
public String remove(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
String temp = strings[index]; // Save to return at end
System.arraycopy(strings, index + 1, strings, index, size - index - 1);
strings[size - 1] = null;
size--;
return temp;
}
Вы изменяете содержимое массива, итерации по нему. При удалении элемента в позиции x элемент в позиции x + 1 получит новую позицию x, но поскольку x уже посещен циклом, следующей итерацией будет позиция x + 1, а элемент, который теперь удерживает позицию x будет пропущен.
Вам нужно сделать что-то вроде показанного здесь: удаление элементов из списка в java
Т.е. реализовать Iterable
и удалить элементы с помощью Iterator
Как только вы начнете изменять один из ваших контейнеров, они больше не параллельны, поэтому вы не удаляете правильные элементы.
Вы можете сделать это так:
int i = 0;
while (i < this.size) {
if (!string.equals(strings[i])) {
remove(i);
} else {
++i;
}
}
Обратите внимание, что когда вы удаляете элемент i
, следующие элементы перемещаются вниз, а следующий элемент теперь находится в позиции i
, поэтому, если вы увеличиваете i
вы пройдете мимо него.
Похож на эту линию -
MyListOfStrings temp= new MyListOfStrings(this);
копирует ссылку списка ввода, а не создает дублирующий список.
Как результат, вы удаляете текущую запись, а затем пропускаете следующую запись (которая теперь является текущей), потому что новый объект ссылается на одни и те же базовые данные.
Вы можете сделать список индексов для удаления, а затем удалить их в конце цикла. Конечно, вы должны удалить в обратном порядке, чтобы исключить такую же проблему.
Для удаления объектов из списка при итерации по нему лучше использовать/реализовать Iterator для вашего списка.
Однако, если вы хотите сделать это без Итератора, вы можете сделать это, уменьшив i-Variable на 1 каждый раз, когда вы удаляете строку из списка:
for (int i=0;i<this.size;i++){
if (string.equals(temp.get(i))!=true){
this.remove(i);
i--;
}
}
Это необходимо, потому что вы копируете я + 1-элемент в i-Position, который, как вам известно, нужно снова проверить.
Вы не должны вызывать операции редактирования во время итерации. Рассмотрим этот список:
1: "1"
2: "2"
3: "3"
4: "4"
Теперь вы хотите сохранить "1"
и начать итерацию:
Первый шаг:
1: "1" <- do nothing
2: "2"
3: "3"
4: "4"
Шаг второй
1: "1"
2: "2" <- remove
3: "3"
4: "4"
результатом будет
1: "1"
2: "3"
3: "4"
Шаг третий
1: "1"
2: "3"
3: "4" <- remove
конечный результат
1: "1"
2: "3"
даже с вашим templist это случай, потому что индекс все еще увеличивается. На шаге 3 вы можете сравнить с "3"
от своего templist, но удалить "4"
из своего фактического списка.