Seite 1 von 1

Loop durch eine gp.Liste elegant umsetzten?

Verfasst: Donnerstag 20. September 2007, 09:58
von meneliel
Hallo :)

Mein Problem: ich brauche das 4. Listenelement einer Liste. An sich nicht das Problem, wenn ich eine schöne Liste hätte, die ich einfach so mit Python erstellt hätte.
Dummerweise geht das nicht. Die Liste hab ich mit GeoprocessingTools erstellt, da ich in der Attributtabelle eines ShapeFiles* auf eine Spalte zugreifen möchte. Dafür gibt es die Möglichkeit über das arcgisscripting Modul mit gp.ListFields() ein Listenobjekt zu erstellen. Die einzelnen Objekte der Liste bekomme ich mit der next() Methode.
Sieht dann z.B so aus:

Code: Alles auswählen

li = gp.ListFields(fc)
l = li.next()
l.name    #Name des Listenobjektes
Genau diesen Namen brauche ich. Mit next() kann ich leider nicht direkt auf das 4. Element zugreifen. Also dachte ich, ich zähle einfach durch:

Code: Alles auswählen

i = 0
while i < 4:
	l = li.next()
	i = i+1

print l.name
...
Ich finde das ziemlich umständlich und weiß nicht ob es pythonisch genug ist. Gibt es eine elegantere, schönere Variante?

Hatte auch noch überlegt, einfach durch die komplette Liste durchzulaufen und den Namen jedes Elementes in eine schöne kleine Liste zu schreiben auf die ich dann direkt zugreifen kann, aber das ist auch zu umständlich, da ich ja nur das 4. Elemten will.


*(ein Vektorformat, ein ShapeFile besteht eigentlich aus mehreren Dateien)

Verfasst: Donnerstag 20. September 2007, 10:41
von BlackJack
Du hast also einen Iterator. Mal sehen ob sich was passendes im `itertools`-Modul findet:

Code: Alles auswählen

from itertools import islice

def get_item(iterable, index):
    return islice(iterable, index, index + 1).next()
Je nach "Länge" des Iterators kannst Du mit `list()` aber auch einfach die Elemente in eine Liste packen und damit dann arbeiten.

Verfasst: Dienstag 25. September 2007, 09:04
von meneliel
Danke für deine Antwort, hab das Probelm aber inzwischen anders gelöst bekommen, hab bei den Geoprocessing Tools langem suchen doch nocht etwas gefunden:

Ich erstelle keine List, sondern erzeuge ein sogenanntes FieldInfo-Objekt, dort kann ich dann über Angabe eines Index direkt auf Spalte x zugreifen. Sieht folgender Maßen aus:

Code: Alles auswählen

import arcgisscripting
gp = arcgisscripting.create()

desc = gp.Describe("int_lyr")
FI = desc.FieldInfo
fc_FID = FI.getFieldName(x)

Ich muss auch gestehen, dass ich das mit den IterTools in Python noch nicht vollständig verstanden habe, da hier eine For - Schleife doch anders aussieht, als gewohnt *schäm*
Muss ich mir noch mal genauer angucken, weil sieht irgendwie schon sehr schön kompakt und einfach aus (wenn man es mal verstanden hätte).

Verfasst: Donnerstag 27. September 2007, 09:41
von meneliel
... irgendwie steht in meinen Büchern nichts zu itertools drin .... *hmpf*

Aber hab einen Teil inzwischen zumindest mit einer for-Schleife hinbekommen.

Von ehemals:

Code: Alles auswählen

desc = gp.describe("lyr")
  fi = desc.FieldInfo
  i = 0
  fi_name = fi.getFieldName(i)
  while fi_name != "KN":
    print fi_name
    i = i+1
    fi_name = fi.getFieldName(i)
  
  i = i+1
  j = fi.count
  print "i:", str(i), "j:", str(j)  
  while i<=j:
    print i
    fi_name = fi.getFieldName(i)
    if fi_name.startswith("Shape_") == 0:
      print fi_name , "wird gelöscht"
      gp.deleteField(int_fc, fi_name)
      i=i+1
    else:
      print fi_name, "kann nicht gelöscht werden"
      break
Sieht es nun so aus:

Code: Alles auswählen

 desc = gp.describe("lyr")
  fi = desc.FieldInfo
  i = i+1
  j = fi.count
  print "i:", str(i), "j:", str(j)  
  for i in xrange(i, j):
    
    fi_name = fi.getFieldName(i)
    if  fi_name.startswith("Shape_"):
      print i, fi_name, "kann nicht geloescht werden"
    elif fi_name == "KN" or fi_name =="KN_1":
      print i, fi_name, "wird nicht geloescht, AGS"
    else :
      print i, fi_name , "wird geloescht"
      gp.deleteField(int_fc, fi_name)
    print ""
Noch nicht so richtig eine Lösung habe ich für den ersten Teil:

Code: Alles auswählen

fi_name = fi.getFieldName(i)
  while fi_name != g_id:
    print fi_name
    i = i+1
    fi_name = fi.getFieldName(i)
denn erst nach g_id fange ich an Felder zu löschen, alle die davor stehen brauche ich. Ich weiß aber auch nicht, an welcher Stelle genau g_id stehen kann, das ist von Datei zu Dtaei unterschiedlich.

Verfasst: Donnerstag 27. September 2007, 10:53
von BlackJack
Ich kenne die API nicht, aber kann man da Felder löschen ohne das sich der Index für die noch vorhandenen Felder ändert?

Hier ist wieder ein Lösungsvorschlag mit `itertools.dropwhile` (sorry, aber ich mag die `itertools` einfach :-)):

Code: Alles auswählen

    field_info = gp.describe('lyr').FieldInfo
    field_names = iter([field_info.getFieldName(i)
                        for i in xrange(field_info.count)])
    dropwhile(lambda name: name != g_id, field_names)
    for field_name in field_names:
        print field_name,
        if field_name.startswith('Shape_'):
            print 'kann nicht geloescht werden'
        elif field_name in ('KN', 'KN_1'):
            print 'wird nicht gelöscht, AGS'
        else:
            print 'wird gelöscht'
            gp.deleteField(int_fc, field_name)
        print

Verfasst: Donnerstag 27. September 2007, 11:48
von meneliel
BlackJack hat geschrieben:Ich kenne die API nicht, aber kann man da Felder löschen ohne das sich der Index für die noch vorhandenen Felder ändert?
Mach ich ja nicht. Ich erstelle ein Layer von einer FeatureClass, springe dort durch die Felder um den jeweiligen Feldnamen zu bekommen und lösche dann in der FeatureClass selber, in dem ich das Feld direkt mit Namen anspreche.
Nach 3 Tagen rumprobieren, wie am Besten scheint das die einfachste Variante zu sein. Das Problem mit den sich ändernden IDs, wenn ich Felder lösche, kann ich so umgehen.


Danke für deinen Vorschlag... ich glaube so langsam hab ichs ... :D

Verfasst: Donnerstag 1. November 2007, 11:36
von meneliel
Hallo,

ich missbrauche gleich mal meinen eignes Thema, da mein neues Problem sich wieder auch eine Liste bezieht (oder soll ich besser ein neues aufmachen?)

Jedenfalls.

Ich habe wieder ein Shapefile oder ne FeatureClass in einer Geodatabase.
Aus dieser Tabelle, will ich nun Werte auslesen und in eine csv speichern, dies allerdings nicht für alle Spalten, sondern nur für einige.

Dafür habe ich mir eine Liste gemacht, mit allen relevanten Spalten, packe die alle in einen String und erstelle mit GP-Tools ein Cursorobjekt, für alle relevanten Spalten, mit dem ich dann Zeilenweise auf die Inhalte der Tabelle zugreifen kann:

Code: Alles auswählen

names_ok = ["a", "b", "c", "d"]
for name in names_ok:
    row_names += name +";"

rows = gp.searchcursor("fc", "", "", row_names)
rows.reset ()
row_cursor = rows.next()

while row_cursor:
    # a)ich würde gern
    for name in names_ok:
        row_csv.append[name]# oder muss ich für ein append vorher eine leere Liste erstellen?

    # geht aber nicht, weil "name" keine gültige Spalte ist
    # b)also muss ich:
    a = row_cursor.a
    b = row_cursor.b
    c = row_cursor.c
    ....
    row_csv = [a,b,c,...]
Und das finde ich ziemlich umständlich. Ich suche nach einer Möglichkeit bei dem Aufruf von row_cursor.spaltenname, den Spaltennamen variabel zu übergeben, damit ich am Ende a) nehmen kann.

Alles andere wäre ziemlich doof. Zumal sich auch die Spalten, die relevant sind mal ändern können.

Verfasst: Donnerstag 1. November 2007, 12:11
von Leonidas
Schau dir doch mal `getattr()` an, dort übergibst du als ersten Parameter das Objekt, als zweiten das Attribut (als String) und bekommst dessen Wert zurück.

Verfasst: Donnerstag 1. November 2007, 12:22
von meneliel
:( ich weiß gerade nicht, wie mir das helfen kann, so kann ich mit name, aber doch auch nicht, den gerade aktuallen Spaltennamen übergeben, der in name gespeichert ist, weil das gp Tool davon ausgeht, das die Spalte dann name heißt.

irgendwie steh ich gerade auf dem Schlauch

Weiß auch nicht, wie ich getattr hier überhaupt verwenden kann.

Verfasst: Donnerstag 1. November 2007, 12:27
von Leonidas
Etwa so:

Code: Alles auswählen

row_csv = list()
for name in names_ok:
    row_csv.append(getattr(row_cursor.name, name))

Verfasst: Donnerstag 1. November 2007, 12:31
von meneliel

Code: Alles auswählen

>>> name
'AGS'
>>> row_cursor.AGS
'11001001'
>>> getattr(row_cursor.name, name)

Traceback (most recent call last):
  File "<pyshell#100>", line 1, in -toplevel-
    getattr(row_cursor.name, name)
RuntimeError: row field name does not exist

EDIT:
AHHHH ich habs :). Gerade Hilfe zu getattr() noch mal gelesen.

Code: Alles auswählen

>>> getattr(row_cursor, name)
'11001001'
Ich kannte das bisher noch gar nicht. Danke dir vielmals für den Tipp, das könnte mir an so mancher Stelle weiterhelfen, wo ich bisher arge Probleme hatte.