Дмитрий
22 уровень
Разбор РЕШЕНИЯ!
Решен
Комментарии (11)
- популярные
- новые
- старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Intoxikot
19 июня 2020, 07:30
Вот смотри здесь я описал решение этой задачи
https://javarush.com/help/48728#discussion
0
(@__@)
18 июня 2020, 16:17полезный
чтобы не было такой боли есть конструкция forEach:
for(Type el : list)
type - тип элемента. в твоей задаче это String
el - название элемента, считай что название переменной.
list - это перебираемый список
для твоей задачи будет вот так:
в таком случае strings.remove() сам считает индексы.
немного про форич
удаление из цикла
+1
(@__@)
18 июня 2020, 16:29
еще, как вариант, можно внутри функции fix создать пустой список.
потом пробежаться по своему и вынести в новый все, что надо по условию.
в конце вернуть новый список.
порой проще сделать через новый, чем копаться в старом.
0
hidden #598481
18 июня 2020, 18:35полезный
Бум! И поймаешь ConcurrentModificationException при попытке изменения списка, который перебираешь фор-ичем. Так делать нельзя. По твоей же ссылке об этом и написано.
Либо перебирай итератором, либо перебирай копию оригинала. Начиная с java8 есть метод removeIf, который может проверить выполнимость предиката и безопасно удалить из списка.
Другой вариант безопасно удалить из списка - перебирать его задом наперед. Просто объявляешь фор от последнего элемента к первому, и никакие сдвиги тебе не страшны: они все будут происходить в уже пройденной части списка.
Что касается возврата нового списка, то тоже не прокатит. Хоть на выходе будет и список с правильным содержанием, но это будет другой объект. А по ТЗ метод должен именно изменять переданный объект.
По-хорошему это вообще должен быть void метод, не знаю зачем его сделали возвращающим список.
+3
(@__@)
18 июня 2020, 18:52
я решил как раз через новый список. и валидатор не возражал.
к тому же многие методы, например для работы со стрингами. возвращают новый список.
так что, как минимум, такой вариант знать полезно.
за итератор спасибо.
я почему-то решил, что форич это сахар для итератора, который под капотом тоже пользует next(). иначе как он перебирает сэты и мапы? :\
Сам же отвечу - видимо у него разные реализации для разных типов :)
0
hidden #598481
18 июня 2020, 19:07
В том-то и дело, что for-each скрывает в себе итератор и не дает к нему прямого доступа, он там как бы приватный, и дает тебе только доступ к результату метода next. Вот что об этом написано в Javadoc:
So when should you use the for-each loop? Any time you can. It really beautifies your code. Unfortunately, you cannot use it everywhere. Consider, for example, the expurgate method. The program needs access to the iterator in order to remove the current element. The for-each loop hides the iterator, so you cannot call remove. Therefore, the for-each loop is not usable for filtering. Similarly it is not usable for loops where you need to replace elements in a list or array as you traverse it. Finally, it is not usable for loops that must iterate over multiple collections in parallel. These shortcomings were known by the designers, who made a conscious decision to go with a clean, simple construct that would cover the great majority of cases.
https://docs.oracle.com/javase/8/docs/technotes/guides/language/foreach.html
0
(@__@)
18 июня 2020, 19:17
хм.. тогда не понимаю.. если он делает некст, значит ему не нужен индекс, а значит можно удалять ремувом. :\
но судя по тому, что НЕЛЬЗЯ. где-то моя логика дает брешь :)
пошел курить доки.
и да! вспомнил еще один вариант, который видел у других. и vk на него намекнул:
это сделать копию списка и пробежать по нему циклом. при этом удалять ненужное из оригинала.
0
hidden #598481
18 июня 2020, 19:26полезный
Ну вот смотри, ты же понимаешь разницу между list.remove(element) и iterator.remove?
list.remove() сломает цикл, если его перебирать, а iterator.remove не сломает.
Я же не напрасно выделил слово "скрывает" в прошлом комментарии. Скрывает - это значит во-первых содержит, и это плюс, а во-вторых не дает к нему прямого доступа, это минус. Ведь ты не можешь написать iterator.remove(), если итератор скрыт, спрятался под капотом фор-ича. Еще раз подчеркну ключевую фразу из дока:
The program needs access to the iterator in order to remove the current element. The for-each loop hides the iterator, so you cannot call remove.
Для удаления нужен доступ к итератору. Доступа нет, он скрыт чехлом for-each. Если спросишь, почему не дали доступ, то в чем тогда вообще было бы отличие от итератора?
+2
(@__@)
18 июня 2020, 19:36
видимо не понимаю разницы.
оба ремува удаляют элемент. в обоих случаях идет смещение и переопределение индекса.
только один крашит цикл, второй нет :\
при том что нексту, вроде как без разницы сколько ячеек там еще осталось. 9 или 10.
т.е. я как раз думал, что ремувы действуют одинаково. а безопасность достигается за счет использования некста вместо индекса..
з.ы я если что понял, как нельзя, а как можно.
но мне интересно знать ПОЧЕМУ оно работает именно так :)
0
(@__@)
19 июня 2020, 04:22
нашел ответ на свой вопрос
если кратко, то при создании итератор запоминает состояние списка. И при изменении списка он проверяет и корректирует это состояние.
А так как в фориче итератор скрыт, до доступа к отслеживанию состояния нет, потому менять список в цикле - больно.
Спасибо содержательную за беседу
0
hidden #598481
19 июня 2020, 07:29
Я же это и писал, что он скрыт)) ну поняли а конце концов друг друга, и хорошо
0