1

I just buried a couple of hours not realizing that I can't do this:

with arcpy.da.SearchCursor(fp_in, ['OBJECTID', 'name']) as cursor:
  objectid = [row[0] for row in cursor]
  name = [row2[1] for row2 in cursor]
  # now do some stuff with those two lists 

the objectid variable comes out as a list with numbers from the feature, as it should. However the name field comes up [] (empty). Apparently I don't know with blocks or list comprehensions because it seems I destroyed the cursor object after first use? I am confused. name IS a field and it exists. I solved this by doing the ugly initiate a blank list and append:

objectid = []
name = []
with arcpy.da.SearchCursor(fp_in, ['OBJECTID', 'name']) as cursor:
  for row in cursor
    objectid.append(row[0])
    name.append(row[1])

But there has to be a prettier way right?

4
  • 2
    Parallel arrays are an odd goal when you could build a dictionary. This feels like a XY Problem. What do you intend to do with the data?
    – Vince
    Jun 2 '20 at 4:57
  • 1
    What is your goal?
    – BERA
    Jun 2 '20 at 6:47
  • my goal is to create a function taking two args: a list of fields i.e. ['OBJECTID', 'name', 'date']` and a nested list of target vals in each field, i.e. name = ['Lebron', 'Sam Perkins'’]. In general fields = [field1, field2…fieldN] and vals = [[f1_vals], [f2_vals]…[fN_vals]]. Then create a df with only rows containing vals present from each field. For example, df = df[df.field1.isin(field1_vals)]. Ultimately trying to avoid stringing arcpy functions and saving features by compiling an idx/OBJECTID list for selecting features from feature layer when all is done. Does that make sense? Jun 2 '20 at 15:27
  • hmmm, I'm a bit ignorant on a basic programming concept it seems Vince. I'll Google it, but what is an XY problem? I see what you are saying though. A dictionary, or directly building a data structure like a Pandas DataFrame is less clunky than saving multiple lists? Thanks. Jun 2 '20 at 15:36
3

From the python docs:

zip() in conjunction with the * operator can be used to unzip a list:

So you could do:

with arcpy.da.SearchCursor(fp_in, ['OBJECTID', 'name']) as cursor:
  rows = [row for row in cursor]    # I don't know if zip() works with cursor (can't test)
  objectid, name = list(zip(*rows)) # If it does work, use objectid, name = list(zip(*cursor))
  # now do some stuff with those two lists 
2
  • 1
    Your solution basically works, but it returns tuples, while it seems that lists are preferred by asking person . Plus, if it is arcmap 10.x then Python 2.x is used, which means we don't have to convert zip result to list, as it is list already. Of course Vince's comment is still valid, I don't understand the essence of the question as well...
    – Szym
    Jun 2 '20 at 6:22
  • A barrage of responses to comments on my end. Thanks for the help everyone! The essence of the question is basically two things: 1) my first comment in response to Vince - how to unpack a cursor object preferably into a dataframe. Getting a list was more of an intermediate step. 2) Generally I didn't realize the cursor object was only accessible once in my first code block: objectid = [row[0] for row in cursor] name = [row2[1] for row2 in cursor] as objectid yields a populated list but name = []. And you are right Syzm, zip did yield tuples which I had to list(tuple)finally. Jun 2 '20 at 15:44
0

Here's what I settled on. It's a function that returns a dataframe with all rows from my desired fields.

def list_unique_fields(fp_feat, field):
    import arcpy
    import pandas as pd

    # turn FIELD into list if not a list
    if isinstance(field, list):
        pass
    else:
        field = [field]
    with arcpy.da.SearchCursor(fp_feat, field) as cursor:
        rows = [row for row in cursor]
        vals = zip(*rows)
        for idx, field in enumerate(field):
            # initiate dictionary for first field
            if 'dict' not in locals():
                dict = {field : vals[idx]}
            else:
                dict[field] = vals[idx]
        df = pd.DataFrame(dict)
    return(df)

Use the function as follows:

fp = 'C:/Users/Zach/GIS/gauge_stations'
field = ['OBJECTID', 'gauge_type']
df = list_unique_fields(fp, field)

...And a dataframe (df) shall be returned

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.