Suite

Comment puis-je utiliser efficacement une compréhension de liste sur un ogr.layer dans une boucle en Python ?

Comment puis-je utiliser efficacement une compréhension de liste sur un ogr.layer dans une boucle en Python ?


Énoncé du problème

J'utilise python 2.7 et ogr 1.11.0 sous Windows 7.

J'ai deux fichiers de formes : un pour les rues et un pour les carrefours. Le fichier de formes des rues contient des champs répertoriant les ID des jonctions de début et de fin, ainsi que des informations supplémentaires sur les rues.

Je dois parcourir chaque carrefour et collecter des informations sur toutes les rues qui y sont délimitées. J'ai commencé avec un filtre spatial, comme ceci :

pour les jonctions dans les jonctions : rues.SetSpatialFilter(junction.GetGeometryRef()) connected_streets = [rue pour la rue dans les rues]

Mais c'était lent (environ 1 seconde par jonction, et j'ai 191 000 jonctions). J'ai donc essayé de tirer parti des champs SRT_JUNC et END_JUNC dans le fichier de formes des routes, pour voir si cela fonctionnerait plus rapidement.

pour la jonction dans les jonctions : jonctionID = jonction.GetField("ID") connected_streets = [rue pour la rue dans les rues if street.GetField("SRT_JUNC") == jonctionID ou street.GetField("END_JUNC") == jonctionID]

La compréhension de liste fonctionne bien dans la première itération de la boucle, mais pour toutes les itérations suivantes, elle ne renvoie rien (ou une liste de longueur zéro ?).

La seule façon de le faire fonctionner est d'ouvrir le pilote et de GetLayer à l'intérieur de la boucle. Mais j'ai un gros fichier de formes et les performances de cette méthode sont également trop lentes.

Je montre quelques exemples simplifiés ci-dessous.

Puis-je faire fonctionner plusieurs compréhensions de listes pour une couche ogr, sans recharger la couche entière à chaque fois ? Si non, pourquoi pas ? (J'accepterais également des suggestions pour une approche totalement différente du problème principal, mais je cherche toujours une explication concernant la compréhension de la liste.)


Exemple 1 : Compréhension de liste sans couche ogr

Le script de base suivant

ma_liste = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] pour x dans la plage(3) : print len([a pour a dans ma_liste])

produit le résultat attendu :

10 10 10

Exemple 2 : Compréhension de liste avec la couche ogr

Le script suivant est parallèle à l'exemple 1, sauf qu'il utilise une couche ogr au lieu d'une simple liste.

depuis osgeo import ogr driver = ogr.GetDriverByName("ESRI Shapefile") dataSource = driver.Open(file, 0) rues = dataSource.GetLayer() pour x in range(3): print len([street for street in street] )

Il produit un inattendu résultat:

191017 0 0

Exemple 3 : déplacez GetLayer à l'intérieur de la boucle

J'ai déplacé l'appel GetLayer dans la boucle :

depuis osgeo import ogr driver = ogr.GetDriverByName("ESRI Shapefile") dataSource = driver.Open(file, 0) for x in range(3): rues = dataSource.GetLayer() print len([street for street in street] )

Mais cela produit toujours le résultat inattendu :

191017 0 0

Exemple 4 : déplacer le pilote. Ouvrir à l'intérieur de la boucle

J'ai également déplacé l'appel Open du pilote dans la boucle :

depuis osgeo import ogr driver = ogr.GetDriverByName("ESRI Shapefile") pour x dans la plage(3) : dataSource = driver.Open(file, 0) rues = dataSource.GetLayer() print len([street for street in roads] )

Et cela produit le résultat attendu :

191017 191017 191017

Je pense que lorsque vous parcourez des fonctionnalités dans une couche gdal, vous utilisez OGRLayer::GetNextFeature(), donc après avoir parcouru toutes les fonctionnalités, la fonctionnalité suivante sera toujours vide. Cela explique pourquoi vous obtenez le résultat escompté lorsque vous appelezdriver.Open(fichier, 0)à l'intérieur de la boucle.

Vous pouvez utiliser OGRLayer::ResetReading() pour commencer par le haut

D'un autre côté, l'itération sur les fonctionnalités sera toujours lente. Faire cela dans postgis n'est pas une option ? ce serait plus rapide

J'espère que cela t'aides

*modifier : ajout d'une référence à ResetReading