Также важно отметить, что 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'):
Позвольте мне привести несколько примеров с некоторыми альтернативами, чтобы избежать 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
очевидное преимущество не имеет чтобы скопировать что-либо, поскольку мы удаляем по мере повторения. Таким образом, это очень эффективно. removeAll
недостатком является то, что мы должны повторять итерацию дважды. Сначала мы итерации в foor-loop искали объект, соответствующий нашим критериям удаления, и как только мы его нашли, мы попросим удалить его из оригинальной коллекции, что означало бы вторую итерационную работу для поиска этого элемента, чтобы убери это. Iterator
помечен как «необязательный» в Javadocs, что означает, что могут быть Iterator
реализации, которые бросают UnsupportedOperationException
, если мы вызываем метод удаления. Таким образом, я бы сказал, что этот подход менее безопасен, чем другие, если мы не можем гарантировать поддержку итератора для удаления элементов. Будет работать только второй подход. Вы можете изменять коллекцию во время итерации только с помощью iterator.remove()
. Все остальные попытки вызовут ConcurrentModificationException
.
Существует также простое решение для «итерации» Collection
и удаления каждого элемента.
List<String> list = new ArrayList<>();
//Fill the list
Он просто соглашается на цикл, пока список не будет пустым, и на каждой итерации мы удалим первый элемент с remove(0)
.
while(!list.isEmpty()){
String s = list.remove(0);
// do you thing
}
Я не считаю, что это улучшилось по сравнению с Iterator
, он все еще должен иметь изменяемый список, но мне нравится простота этого решения .
Я бы выбрал второй, так как вам не нужно делать копию памяти, и Iterator работает быстрее. Таким образом, вы сохраняете память и время.
Есть ли какие-либо причины предпочесть один подход по сравнению с другим
blockquote>. Первый подход будет работать, но имеет очевидные накладные расходы на копирование списка.
Второй подход не будет работать, потому что многие контейнеры не допускают модификации во время итерации. Это включает в себя
ArrayList
.Если единственной модификацией является удаление текущего элемента, вы можете сделать работу второго подхода с помощью
itr.remove()
(т. е. использовать метод итератораremove()
, а не контейнер ). Это был бы мой предпочтительный метод для итераторов, которые поддерживают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 ()
get(i)
, вы должны посетить все узлы, пока не достигнете i
.
– Edwin Dalorzo
3 May 2012 в 15:59
Foo.remove(i);
вы должны делать i--;
?
– Bertie Wheen
19 March 2013 в 23:38
Вы не можете сделать второе, потому что, даже если вы используете метод remove()
на Iterator , , вы получите исключение, брошенное .
Лично я предпочел бы первый для всех экземпляров Collection
, несмотря на дополнительное подслушивание создания нового Collection
, я нахожу его менее склонным к ошибке во время редактирования другими разработчиками. В некоторых реализациях Collection поддерживается Iterator remove()
, а другой - нет. Вы можете прочитать больше в документах для Iterator .
Третий вариант - создать новый Collection
, перебрать исходный текст и добавить все элементы первого Collection
ко второму Collection
, которые являются не для удаления. В зависимости от размера Collection
и количества удалений это может значительно экономить на памяти по сравнению с первым подходом.
В Java 8 существует другой подход. Коллекция # removeIf
например:
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.removeIf(i -> i > 2);
removeAll(filtered)
. Для этого будет ярлыкremoveIf(b -> b.getIsbn().equals(other))
– ifloop 27 March 2018 в 14:20