Для цикла не проходит через весь индекс [дубликат]

Также важно отметить, что ord ('q') может возвращать разные числа, если активирован NumLock (возможно, это также происходит с другими клавишами). Например, при нажатии c код:

key = cv2.waitKey(10) 
print(key) 

возвращает

 1048675 when NumLock is activated 
 99 otherwise

Преобразование этих двух чисел в двоичный файл можно увидеть:

1048675 = 100000000000001100011
99 = 1100011

Как мы видим, последний байт идентичен. Затем необходимо взять только этот последний байт, поскольку остальное вызвано из-за состояния NumLock. Таким образом, мы выполняем:

key = cv2.waitKey(33) & 0b11111111  
# 0b11111111 is equivalent to 0xFF

, а значение ключа останется прежним, и теперь мы можем сравнить его с любой клавишей, которую мы хотели бы задать, например, ваш вопрос

if key == ord('q'):
116
задан user1329572 3 May 2012 в 14:21
поделиться

8 ответов

Позвольте мне привести несколько примеров с некоторыми альтернативами, чтобы избежать ConcurrentModificationException.

Предположим, что у нас есть следующий сборник книг

List<Book> books = new ArrayList<Book>();
books.add(new Book(new ISBN("0-201-63361-2")));
books.add(new Book(new ISBN("0-201-63361-3")));
books.add(new Book(new ISBN("0-201-63361-4")));

Сбор и удаление

Первый метод состоит в том, чтобы собрать все объекты, которые мы хотим удалить (например, с помощью расширенного цикла), и после завершения итерации мы удалим все найденные объекты.

ISBN isbn = new ISBN("0-201-63361-2");
List<Book> found = new ArrayList<Book>();
for(Book book : books){
    if(book.getIsbn().equals(isbn)){
        found.add(book);
    }
}
books.removeAll(found);

Это Предположим, что операция, которую вы хотите сделать, - «удалить».

Если вы хотите «добавить», этот подход также будет работать, но я бы предположил, что вы будете перебирать другую коллекцию, чтобы определить, какие элементы вы хотите добавить во вторую коллекцию, а затем выпустить addAll метод в конце.

Использование ListIterator

Если вы работаете со списками, другой метод заключается в использовании ListIterator, который поддерживает удаление и добавление элементов во время самой итерации .

ListIterator<Book> iter = books.listIterator();
while(iter.hasNext()){
    if(iter.next().getIsbn().equals(isbn)){
        iter.remove();
    }
}

Опять же, я использовал метод «remove» в приведенном выше примере, который, по-видимому, подразумевал ваш вопрос, но вы также можете использовать его метод add для добавления новых элементов во время итерации.

Использование JDK 8

Для тех, кто работает с Java 8 или превосходными версиями, есть несколько других методов, которые вы могли бы использовать, чтобы воспользоваться им.

Вы можете использовать новый метод removeIf в базовом классе Collection:

ISBN other = new ISBN("0-201-63361-2");
books.removeIf(b -> b.getIsbn().equals(other));

Или использовать новый поток API:

ISBN other = new ISBN("0-201-63361-2");
List<Book> filtered = books.stream()
                           .filter(b -> b.getIsbn().equals(other))
                           .collect(Collectors.toList());

В этом последнем случае фильтрующие элементы из коллекции, вы переназначаете оригиналы наальную ссылку на фильтрованную коллекцию (т.е. books = filtered) или использовали фильтрованную коллекцию для removeAll найденных элементов из исходной коллекции (например, books.removeAll(filtered)).

Использовать подсписку или подмножество

Существуют и другие альтернативы: Что ж. Если список отсортирован и вы хотите удалить последовательные элементы, вы можете создать подсписку, а затем очистить его:

books.subList(0,5).clear();

Так как подсписщик поддерживается исходным списком, это будет эффективным способом удаления это подмножество элементов.

Нечто подобное может быть достигнуто с помощью отсортированных множеств с использованием метода NavigableSet.subSet или любого из предложенных там методов разрезания.

Соображения:

Какой метод вы используете, может зависеть от того, что вы собираетесь делать

  • Метод сбора и removeAl работает с любой коллекцией (Collection, List, Set и т. Д.).
  • Метод ListIterator, очевидно, работает только со списками при условии, что их реализация ListIterator предлагает поддержку для операций добавления и удаления.
  • Подход Iterator будет работать с любым типом коллекции, но он поддерживает только операции удаления.
  • При подходе ListIterator / Iterator очевидное преимущество не имеет чтобы скопировать что-либо, поскольку мы удаляем по мере повторения. Таким образом, это очень эффективно.
  • Пример потока JDK 8 на самом деле ничего не удаляет, но ищет нужные элементы, а затем мы заменили исходную ссылку на сборку на новую, и пусть старый будет собран мусором. Итак, мы повторяем только один раз над сборником, и это будет эффективно.
  • В подходе сбора и removeAll недостатком является то, что мы должны повторять итерацию дважды. Сначала мы итерации в foor-loop искали объект, соответствующий нашим критериям удаления, и как только мы его нашли, мы попросим удалить его из оригинальной коллекции, что означало бы вторую итерационную работу для поиска этого элемента, чтобы убери это.
  • Я думаю, что стоит упомянуть, что метод remove интерфейса Iterator помечен как «необязательный» в Javadocs, что означает, что могут быть Iterator реализации, которые бросают UnsupportedOperationException, если мы вызываем метод удаления. Таким образом, я бы сказал, что этот подход менее безопасен, чем другие, если мы не можем гарантировать поддержку итератора для удаления элементов.
229
ответ дан Edwin Dalorzo 18 August 2018 в 23:02
поделиться
  • 1
    первый раз, используя итератор, и он работает – Jemshit Iskenderov 11 May 2016 в 14:13
  • 2
    Браво! это окончательное руководство. – Magno C 18 January 2017 в 12:47
  • 3
    Это прекрасный ответ! Спасибо. – Wilhelm 17 March 2018 в 03:37
  • 4
    В вашем параграфе о потоках JDK8 вы указываете removeAll(filtered). Для этого будет ярлык removeIf(b -> b.getIsbn().equals(other)) – ifloop 27 March 2018 в 14:20

Будет работать только второй подход. Вы можете изменять коллекцию во время итерации только с помощью iterator.remove(). Все остальные попытки вызовут ConcurrentModificationException.

4
ответ дан AlexR 18 August 2018 в 23:02
поделиться
  • 1
    Первый подход также работает. – user1329572 3 May 2012 в 14:09
  • 2
    Первая попытка повторяется на копии, то есть он может изменить оригинал. – Colin D 3 May 2012 в 14:10
  • 3
    Первый подход будет работать, поскольку вы повторяете копию. – Jon 3 May 2012 в 14:13

Существует также простое решение для «итерации» Collection и удаления каждого элемента.

List<String> list = new ArrayList<>();
//Fill the list

Он просто соглашается на цикл, пока список не будет пустым, и на каждой итерации мы удалим первый элемент с remove(0).

while(!list.isEmpty()){
    String s = list.remove(0);
    // do you thing
}

Я не считаю, что это улучшилось по сравнению с Iterator, он все еще должен иметь изменяемый список, но мне нравится простота этого решения .

-1
ответ дан AxelH 18 August 2018 в 23:02
поделиться

Я бы выбрал второй, так как вам не нужно делать копию памяти, и Iterator работает быстрее. Таким образом, вы сохраняете память и время.

0
ответ дан Calin Andrei 18 August 2018 в 23:02
поделиться
  • 1
    « Итератор работает быстрее ». Что-нибудь, чтобы поддержать это требование? Кроме того, объем памяти для создания копии списка очень тривиален, тем более, что он будет ограничен внутри метода и будет собирать мусор почти сразу. – user1329572 3 May 2012 в 14:17
  • 2
    никоим образом, копия памяти и сбор мусора не являются огромными накладными расходами – Betlista 3 May 2012 в 15:57
  • 3
    В первом подходе недостатком является то, что мы должны повторять итерацию дважды. Мы перебираем петлю в поисках элемента, и как только мы его найдем, мы попросим удалить его из исходного списка, что означало бы вторую итерационную работу для поиска данного элемента. Это подтвердит утверждение, что по крайней мере в этом случае подход итератора должен быть быстрее. Мы должны учитывать, что только структурное пространство коллекции создается тем, что объекты внутри коллекций не копируются. Обе коллекции будут ссылаться на одни и те же объекты. Когда GC происходит, мы не можем сказать !!! – Edwin Dalorzo 3 May 2012 в 16:14

Есть ли какие-либо причины предпочесть один подход по сравнению с другим

. Первый подход будет работать, но имеет очевидные накладные расходы на копирование списка.

Второй подход не будет работать, потому что многие контейнеры не допускают модификации во время итерации. Это включает в себя ArrayList .

Если единственной модификацией является удаление текущего элемента, вы можете сделать работу второго подхода с помощью itr.remove() (т. е. использовать метод итератора remove(), а не контейнер ). Это был бы мой предпочтительный метод для итераторов, которые поддерживают remove().

11
ответ дан Community 18 August 2018 в 23:02
поделиться
  • 1
    К сожалению, извините ... подразумевается, что я буду использовать метод удаления iterator, а не контейнер. И сколько накладных расходов создает копирование списка? Этого не может быть много, и поскольку он привязан к методу, его нужно собирать мусор довольно быстро. См. Edit .. – user1329572 3 May 2012 в 14:20
  • 2
    @aix Я думаю, что стоит упомянуть, что метод remove интерфейса Iterator помечается как необязательный в Javadocs, что означает, что могут быть реализаторы Iterator, которые могут бросать UnsupportedOperationException. Таким образом, я бы сказал, что этот подход менее безопасен, чем первый. В зависимости от применений, предназначенных для использования, первый подход может быть более подходящим. – Edwin Dalorzo 3 May 2012 в 14:53

почему бы не это?

for( int i = 0; i < Foo.size(); i++ )
{
   if( Foo.get(i).equals( some test ) )
   {
      Foo.remove(i);
   }
}

И если это карта, а не список, вы можете использовать keyset ()

-1
ответ дан Drake Clarris 18 August 2018 в 23:02
поделиться
  • 1
    Этот подход имеет много серьезных недостатков. Во-первых, каждый раз, когда вы удаляете элемент, индексы реорганизуются. Поэтому, если вы удалите элемент 0, то элемент 1 станет новым элементом 0. Если вы собираетесь это сделать, по крайней мере, сделайте это назад, чтобы избежать этой проблемы. Во-вторых, не все реализации List предлагают прямой доступ к элементам (как это делает ArrayList). В LinkedList это было бы чрезвычайно неэффективно, потому что каждый раз, когда вы выдаете get(i), вы должны посетить все узлы, пока не достигнете i. – Edwin Dalorzo 3 May 2012 в 15:59
  • 2
    Никогда не рассматривал это, поскольку я обычно использовал его, чтобы удалить один элемент, который я искал. Хорошо знать. – Drake Clarris 3 May 2012 в 16:02
  • 3
    Я опаздываю на вечеринку, но, конечно, в блоке if после Foo.remove(i); вы должны делать i--;? – Bertie Wheen 19 March 2013 в 23:38
  • 4
    потому что он прослушивается – Jack 20 July 2017 в 13:31

Вы не можете сделать второе, потому что, даже если вы используете метод remove() на Iterator , , вы получите исключение, брошенное .

Лично я предпочел бы первый для всех экземпляров Collection, несмотря на дополнительное подслушивание создания нового Collection, я нахожу его менее склонным к ошибке во время редактирования другими разработчиками. В некоторых реализациях Collection поддерживается Iterator remove(), а другой - нет. Вы можете прочитать больше в документах для Iterator .

Третий вариант - создать новый Collection, перебрать исходный текст и добавить все элементы первого Collection ко второму Collection, которые являются не для удаления. В зависимости от размера Collection и количества удалений это может значительно экономить на памяти по сравнению с первым подходом.

1
ответ дан Jon 18 August 2018 в 23:02
поделиться
  • 1
    Он использует итератор списка, поэтому метод удаления будет работать. – Levent Divilioglu 21 June 2017 в 03:37

В Java 8 существует другой подход. Коллекция # removeIf

например:

List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);

list.removeIf(i -> i > 2);
8
ответ дан Santhosh 18 August 2018 в 23:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: