1

I have a dataset that contains a field with a range of numbers (e.g. 1, 2, 3-6) as well as other fields. I've used python to expand the range field into discrete numbers (e.g. 1, 2, 3, 4, 5, 6) stored in a list in python. I would like to insert rows (6 in this example) with the range values. The values from the other fields would be copied for each new row, for each row in the table.

Row Example

| A | 1, 2, 3-6 | xxa | xxb |

to

| A | 1 | xxa | xxb |
| A | 2 | xxa | xxb |
| A | 3 | xxa | xxb |
| A | 4 | xxa | xxb |
| A | 5 | xxa | xxb |
| A | 6 | xxa | xxb |

I have adapted the code written by @Aaron. The code below works for the first row, but I would like it to read every row in the input table. In other words, it is not advancing throughout the table. I think I need to add another for loop at the beginning of insert_rows().

# import libraries


import arcpy
import os

arcpy.env.overwriteOutput = True


tbl = arcpy.GetParameterAsText(0)


def extractit(str):
    """
    Creates a list (e.g. [1,2,3,4,5,6] from string such as '1, 2, 3-6'
    """
    parts = str.replace(" ", "").split(",")

    numbers = []
    for part in parts:
        if '-' in part:
            p = part.split("-")
            numbers.extend(list(range(int(p[0]), int(p[1]) + 1)))
        else:
            numbers.append(int(part))

    return numbers



def create_table(tbl):
    """
        Creates a duplicate (but empty) table
        because we do not want to alter the original
        """
    arcpy.CreateTable_management(os.path.dirname(tbl), os.path.basename(tbl) + "_altered_v2", template=tbl)

    arcpy.DeleteRows_management(tbl + "_altered_v2")


def insert_rows(tbl):
        """
        Insert rows into new table
        """
        # Get row value in original table
        row = [row for row in arcpy.da.SearchCursor(tbl, ["MERIDIAN", "TOWNSHIP", "RANGE", "TOWNSHIP_D", "RANGE_D",
                                                          "SUBDIVIS", "NOTES_SU",
                                                          "BLMSERIA", "CATEGORY", "ACREAGE", "EXCLUSIO", "VILL_BLK",
                                                          "CONV_DAT", "IC_PAT_N", "ENCUMBRA"])][0]

        numbers = extractit(row[5])  # Extract number field

        cursor = arcpy.da.InsertCursor(tbl + "_altered_v2", ["MERIDIAN", "TOWNSHIP", "RANGE", "TOWNSHIP_D", "RANGE_D",
                                                             "SUBDIVIS", "NOTES_SU",
                                                             "BLMSERIA", "CATEGORY", "ACREAGE", "EXCLUSIO", "VILL_BLK",
                                                             "CONV_DAT", "IC_PAT_N", "ENCUMBRA"])

        for number in numbers:
            row_value = (row[0], row[1], row[2], row[3], row[4], str(number), row[6], row[7], row[8], row[9], row[10],
                         row[11], row[12], row[13], row[14])
            cursor.insertRow(row_value)

        # Delete cursor object
        del cursor


if __name__ == '__main__':
    create_table(tbl)
    insert_rows(tbl)
  • 1
    Are you wanting to duplicate the geometry in your first example so that one feature becomes six? – Aaron Mar 14 at 2:09
  • 1
    That's how I read it @Aaron.. I would do this from a source to a destination shapefile (use arcpy.Select_analysis(InPoints,OutPoints,'FID=(FID+1)') to create an empty shapefile with the same CRS and fields) with a dreaded double cursor (arcpy.da.SeachCursor(InPoints,'*') and arcpy.da.InsertCursor(OutPoints,'*') copy all other values and change the specific value for each in the list and then insertRow.. just remember that the shape needs to be unpacked then packed again because it belongs to a different feature class. – Michael Stimson Mar 14 at 4:37
  • @MichaelStimson Agreed, it is a good practice to create a dupe feature class. – Aaron Mar 14 at 4:45
  • I changed the code to meet your requirements. Like you indicated, it only required a for loop. – Aaron Mar 14 at 23:36
1

Here is one approach. There are three main components:

  1. extractit() manipulates unruly strings such as '1, 2, 3-6'
  2. create_fc() creates a new featureclass so as not to alter the original
  3. insert_rows() puts all the pieces together

import arcpy, os

fc = r'C:\temp\test.gdb\temp'

def extractit(str):
    """
    Creates a list from string such as '1, 2, 3-6'
    """
    parts = str.replace(" ", "").split(",")

    numbers = []
    for part in parts:
        if '-' in part:
            p = part.split("-")
            numbers.extend(list(range(int(p[0]), int(p[1]) + 1)))
        else:
            numbers.append(int(part))

    return numbers

def create_fc(fc):
    # Create a new featureclass
    arcpy.CreateFeatureclass_management(os.path.dirname(fc), os.path.basename(fc) + "_altered", template = fc, spatial_reference = fc)

    # Delete Rows
    arcpy.DeleteRows_management(fc + "_altered")

def insert_rows(fc):
    # Get row value in original fc
    rows =[row for row in arcpy.da.SearchCursor(fc, ["field1", "field2", "field3", "field4", "SHAPE@"])]

    for row in rows:
        numbers = extractit(row[1]) # Extract number field

        cursor = arcpy.da.InsertCursor(fc + "_altered", ["field1", "field2", "field3", "field4", "SHAPE@"])

        for number in numbers:
            row_value = (row[0], str(number), row[2], row[3], row[4])
            cursor.insertRow(row_value)

        # Delete cursor object
        del cursor

if __name__ == '__main__':
    create_fc(fc)
    insert_rows(fc)

Before

enter image description here

After

enter image description here

  • 1
    Spectacular! There's a few very good pearls of wisdom in that code. – Michael Stimson Mar 14 at 5:28

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.