5

I need code that loops between each pair of features in sequence (feature 1 with feature 2, feature 2 with feature 3...) but using only a for, I searched the forum and found similar code but with two "for" and one "if", having to go through the entire list again every time the loop happens, would there be a way for me to do this with just one for? I tried using something like "next feature" but it failed.

The original code:

iter1 = layer.getFeatures()
for feature1 in iter1:
    p1 = feature1.geometry().asPoint()
    # loop all points again:
    iter2 = layer.getFeatures()
    for feature2 in iter2:
        # following line creates lines from one feature to previous feature:
        if feature2.id() == feature1.id() + 1:
            # create new line feature:
            p2 = feature2.geometry().asPoint()
            l = QgsGeometry.fromPolylineXY([p1,p2])
            linha = QgsFeature()
            linha.setGeometry(l)
            linha.setAttributes([l.length()])
            pr.addFeature(linha)

My code attempt:

features = layer.getFeatures()
for index, actualFeature in enumerate(features):
    p1 = actualFeature.geometry().asPoint()
    # loop all points again:
    nextFeature = features.index()+1
# create new line feature:
p2 = nextFeature.geometry().asPoint()
l = QgsGeometry.fromPolylineXY([p1,p2])
linha = QgsFeature()
linha.setGeometry(l)
linha.setAttributes([l.length()])
pr.addFeature(linha)


vl.updateFields() QgsProject.instance().addMapLayer(vl)

But one of the problems is that QgsFeatureIterator object has no attribute 'index', and I think I didn't use PyQGIS correctly. I'm still new to this language, could anyone correct the code to my idea?

Mestrexama
  • 91
  • 4
  • 3
    I doubt you need an exotic looping construct. Just maintain a "previous" variable, initialized to None , then handle initialization on the first iteration, compare actual to previous and put a previous = actual at the end of the loop. Try it on something simple first, like a range(10) then step up to features. – Vince Dec 12 '23 at 03:59
  • I think I managed to solve the problem, I put it in the edit of the question, thanks for the help – Mestrexama Dec 16 '23 at 05:09
  • Please, put your solution as a valid answer instead of the edit. – Taras Dec 16 '23 at 07:35
  • Sorry, I just added it as a valid answer – Mestrexama Dec 16 '23 at 12:50

3 Answers3

7

You can use zip and indexing:

layer = iface.activeLayer()
featurelist = [f for f in layer.getFeatures()] #List all features

for featurepair in zip(featurelist[::2], featurelist[1::2]): f1, f2 = featurepair print(f1["id"], f2["id"])

enter image description here

BERA
  • 72,339
  • 13
  • 72
  • 161
5

In most latest QGIS versions like QGIS 3.34.1 Prizren​, it should come with the pairwise() function from the itertool module. Since Python 3.10.

# imports
from itertools import pairwise
from qgis.core import QgsProject

getting a layer by its name

layer = QgsProject.instance().mapLayersByName("YOUR_LAYER_NAME")[0]

a list of all features in the layer

features = [feat for feat in layer.getFeatures()]

looping over pairs of features

for pair in pairwise(features): feat1, feat2 = pair[0], pair[1] print(feat1["id"], feat2["id"])

For earlier version of QGIS, one can use the following approach:

# imports
from qgis.core import QgsProject

getting a layer by its name

layer = QgsProject.instance().mapLayersByName("YOUR_LAYER_NAME")[0]

a list of all features in the layer

features = [feat for feat in layer.getFeatures()]

looping over pairs of features

for i in range(len(features) - 1): feat1, feat2 = features[i], features[i + 1] print(feat1["id"], feat2["id"])

Keep in mind, that features in the may not come sorted, therefore one may find this thread useful: Sorting features by attribute using PyQGIS


References:

Taras
  • 32,823
  • 4
  • 66
  • 137
2

I solved the problem, here's the new code:

from qgis.core import QgsProject, QgsGeometry

layer = QgsProject.instance().mapLayersByName("YOUR_LAYER_NAME")[0] features = [f for f in layer.getFeatures()]

for index, actualFeature in enumerate(features[:-1]): p1 = actualFeature.geometry().asPoint() # loop all points again: nextFeature = features[index+1] # create new line feature: p2 = nextFeature.geometry().asPoint() l = QgsGeometry.fromPolylineXY([p1,p2]) linha = QgsFeature() linha.setGeometry(l) linha.setAttributes([l.length()]) pr.addFeature(linha)

vl.updateFields() QgsProject.instance().addMapLayer(vl)

Taras
  • 32,823
  • 4
  • 66
  • 137
Mestrexama
  • 91
  • 4
  • So happy to hear, that you found a solution to your own problem! It is a pleasure to see how people learn and educate themself :) – Taras Dec 16 '23 at 13:01