警告

本节包含从C++自动翻译到Python的代码片段,可能包含错误。

Qt中的Java风格迭代器#

Qt容器中的Java风格迭代器。

Java风格的迭代器#

对于每个容器类,有两种Java风格迭代器数据类型:一种提供只读访问,另一种提供读写访问。

注意

应当使用STL风格的迭代器编写新代码,因为这些迭代器更高效,可以与Qt和STL的泛型算法一起使用。

容器

只读迭代器

读写迭代器

QList <T>, QQueue <T>, QStack <T>

QListIterator <T>

QMutableListIterator <T>

QSet <T>

QSetIterator <T>

QMutableSetIterator <T>

QMap <Key, T>, QMultiMap <Key, T>

QMapIterator <Key, T>

QMutableMapIterator <Key, T>

QHash <Key, T>, QMultiHash <Key, T>

QHashIterator <Key, T>

QMutableHashIterator <Key, T>

在这次讨论中,我们将重点讨论QListQMap。对于QSet的迭代器类型与QList的迭代器接口完全相同;同样地,对于QHash的迭代器类型与QMap的迭代器接口也相同。

STL风格的迭代器不同,Java风格的迭代器是指向元素之间的位置,而不是直接指向元素。因此,它们可能指向容器的最前面(在第一个元素之前),指向容器的最后面(在最后一个元素之后),或者位于两个元素之间。下图中用红色箭头显示了包含四个元素的列表的有效迭代器位置

../_images/javaiterators1.png

以下是一个遍历QList < QString >中所有元素的典型循环,并按顺序执行

list = {"A", "B", "C", "D"}
i = QListIterator(list)
while i.hasNext():
    s = i.next()

其工作原理如下:要遍历的QList作为参数传递给QListIterator构造函数。此时,迭代器位于列表第一个元素之前(在项目“A”之前)。然后我们调用hasNext()来检查迭代器后面是否有项目。如果有,我们调用next()跳过该项。次()函数返回跳过的项。对于QList < QString >,该项的类型是QString

以下是如何在QList中反向迭代的示例

i = QListIterator(list)
i.toBack()
while i.hasPrevious():
    s = i.previous()

代码与正向迭代是对称的,不同之处在于我们首先调用toBack()来将迭代器移动到列表最后一个元素之后。

下图说明了调用迭代器的next()previous()的效果

../_images/javaiterators2.png

以下表格总结了QListIterator API

函数

行为

toFront()

将迭代器移动到列表的前端(在第一个元素之前)

toBack()

将迭代器移动到列表的后端(在最后一个元素之后)

hasNext()

如果迭代器不在列表的末尾,则返回true

next()

返回下一个元素并向前移动迭代器一个位置

peekNext()

返回下一个元素,但不移动迭代器

hasPrevious()

如果迭代器不在列表的开始位置,则返回true

previous()

返回上一个元素并将迭代器向后移动一个位置

peekPrevious()

返回上一个元素,但不移动迭代器

QListIterator在遍历时不提供插入或删除列表项目的方法。要完成此操作,必须使用QMutableListIterator。以下是一个使用QMutableListIteratorQList <int>中删除所有奇数的示例

i = QMutableListIterator(list)
while i.hasNext():
    if i.next() % 2 != 0:
        i.remove()

循环中的next()调用每次都会进行。它会跳过列表中的下一个项。调用remove()函数将移除我们跳过的最后一个项。对remove()的调用不使迭代器失效,因此可以安全地继续使用它。这种方法在向后迭代时也完全一样

i = QMutableListIterator(list)
i.toBack()
while i.hasPrevious():
    if i.previous() % 2 != 0:
        i.remove()

如果我们只想修改现有项的值,我们可以使用setValue()。在下面的代码中,我们将任何大于128的值替换为128

i = QMutableListIterator(list)
while i.hasNext():
    if i.next() > 128:
        i.setValue(128)

remove()一样,setValue()作用于我们跳过的最后一个项。如果我们正向迭代,这是迭代器之前的项;如果我们反向迭代,这是迭代器之后的项。

next()函数返回列表中项的非const引用。对于简单操作,我们甚至不需要setValue()

i = QMutableListIterator(list)
while i.hasNext():
    i.next() *= 2

如上所述,QSet的迭代器类与QList的迭代器类具有完全相同的API。我们现在将转向QMapIterator,它有些不同,因为它在(key, value)对上迭代。

QListIterator一样,QMapIterator提供了toFront()toBack()hasNext()next()peekNext()hasPrevious()previous()peekPrevious()。通过在next(),peekNext(),previous()或peekPrevious()返回的对象上调用key()value(),可以提取键和值组件。

下面的示例删除了所有以“City”结尾的CAPITAl的(CAPITAl,国家)对

QMap<QString, QString> map = {
    {"Paris", "France"},
    {"Guatemala City", "Guatemala"},
    {"Mexico City", "Mexico"},
    {"Moscow", "Russia"}

...
QString> = QMutableMapIterator<QString,(map)
while i.hasNext():
    if i.next().key().endsWith("City"):
        i.remove()

QMapIterator还提供了直接对迭代器执行的key()value()函数,它们返回迭代器跳过的最后一个项的键和值。例如,以下代码将一个QMap的内容复制到一个QHash

QWidget = QMap<int,()
QWidget = QHash<int,()
QWidget = QMapIterator<int,(map)
while i.hasNext():
    i.next()
    hash.insert(i.key(), i.value())

如果我们想遍历具有相同值的所有项,我们可以使用findNext()findPrevious()。以下是一个示例,其中我们删除所有具有特定值的项

QWidget = QMutableMapIterator<int,(map)
while i.findNext(widget):
    i.remove()