There is a script tool called "Concatenate Row Values" that does exactly what you want. It is available for download here. There is also a blog entry about this script tool. All you have to do is add a field to your FeatureClass where the concatenated values will be written and summarize.
For those interested in seeing the script:
# Import system modules
import sys, traceback, arcpy
#Define AddPrintMessage
def AddPrintMessage(msg, severity):
print msg
if severity == 0: arcpy.AddMessage(msg)
elif severity == 1: arcpy.AddWarning(msg)
elif severity == 2: arcpy.AddError(msg)
try:
# Set the parameters
InputTable = arcpy.GetParameterAsText(0)
if (InputTable == ''):
arcpy.AddError("No input provided")
CaseField = arcpy.GetParameterAsText(1)
if (CaseField == ''):
arcpy.AddError("No iterate field provided. The iteration will be based on unique values")
ReadFromField = arcpy.GetParameterAsText(2)
if (ReadFromField == ''):
arcpy.AddError("No field provided to read the values from")
CopyToField = arcpy.GetParameterAsText(3)
if (CopyToField == ''):
arcpy.AddError("No field provided to copy the values to")
Delimiter = arcpy.GetParameterAsText(4)
# Validate the inputs that are provided for field type.
# A text field value can only be copied to a text type field, and
# The numric field values with a delimiter can only be copied to a text type field.
# Short Integer can be copied to field of type text, short integer, long integer, single or double without a delimiter.
if arcpy.ListFields(InputTable, ReadFromField)[0].type == "String":
if arcpy.ListFields(InputTable, CopyToField)[0].type == "String":
""
else:
arcpy.AddError("Copy To Field must be of type text when Read From Field is of type text.")
else:
if arcpy.ListFields(InputTable, CopyToField)[0].type == "String":
""
else:
if Delimiter != "":
arcpy.AddError("Copy To Field must be of type text when Read From Field is of type numeric or date and you are using a delimiter.")
if Delimiter == "":
if arcpy.ListFields(InputTable, ReadFromField)[0].type == "SmallInteger":
if arcpy.ListFields(InputTable, CopyToField)[0].type in ["Integer", "SmallInteger", "Single", "Double"]:
""
else:
if arcpy.ListFields(InputTable, CopyToField)[0].type == "Date":
arcpy.AddError("Copy To Field must be of type text.")
if arcpy.ListFields(InputTable, ReadFromField)[0].type == "Integer":
if arcpy.ListFields(InputTable, CopyToField)[0].type in ["SmallInteger", "Integer", "Single", "Double", "Date"]:
arcpy.AddError("Copy To Field must be of type text.")
else:
if arcpy.ListFields(InputTable, ReadFromField)[0].type in ["Single", "Double" , "Date"]:
if arcpy.ListFields(InputTable, CopyToField)[0].type in ["Integer", "SmallInteger", "Single", "Double" , "Date"]:
arcpy.AddError("Copy To Field must be of type text.")
# Create an empty dictionary.
dictionary = {}
# Create a variable and set its value to the last row value. The first one is -1 which means no row before the first.
lastid = -1
# Create an empty variable which will store the value of the last row in the code below.
lastvalue = ""
# Insert Search cursor on a feature class or table to iterate through row objects and extract field values.
# Sort values of a Search Cursor based on the CaseField and ReadFromField in ascending order.
# Define what will happen once the curser moves through each row.
# While it is in each row it will get the value of CaseField field that you are using as id to iterate.
# While it is in row it will also get the value of the ReadFromField field that you want to concatenate.
# Set the value of the dictionary to the values read by the cursor from the ReadFromField.
# Set an if condition for what should the cursor do when it reads through fields with same ID or the CaseField value.
# In if condition set the new value to last value of the ReadFromField + the defined delimiter + the new value that is read.
# Again set the dictionary value to this new value.
# Set the loop to have the lastid to the id that you got from getValue before it goes through the seconnd loop and so on...
# Set the loops last value variable to the last value that was read such that it starts with that last value for the second loop and so on...
cur1 = arcpy.SearchCursor(InputTable, "", "", "", CaseField +" A;" + ReadFromField +" A")
for row in cur1:
id = row.getValue(CaseField)
value = row.getValue(ReadFromField)
dictionary[id] = value
if id == lastid:
value = str(lastvalue) + Delimiter + str(value)
dictionary[id] = value
lastid = id
lastvalue = value
# Delete cursor and row objects to remove the lock on the data that will remain until either the
# script completes or the cursor object is deleted.
del cur1, row
# Insert Update cursor to update or delete rows on the specified feature class, shapefile, or table.
# Define what will happen once the curser moves through each row.
# While you are in each row set the cursor to get the value of the CaseField that is used as Id to iterate.
# Set the value of the field that the concatenated values should be written to with the dictionary values that you concatenated in the code above.
# Set the cursor to update the row values with the dictionary values.
cur2 = arcpy.UpdateCursor(InputTable)
for row in cur2:
id = row.getValue(CaseField)
row.setValue(CopyToField, dictionary[id])
cur2.updateRow(row)
# Delete cursor and row objects to remove the lock on the data that will remain until either the
# script completes or the cursor object is deleted.
del cur2, row
# If you are using the tool in ModelBuilder, set the derived output parameter to the value
# of input table so that it is not empty and can be used with other tools.
arcpy.SetParameterAsText(5, str(InputTable))
except:
tb = sys.exc_info()[2]
tbinfo = traceback.format_tb(tb)[0]
pymsg = "PYTHON ERRORS:\nTraceback Info:\n" + tbinfo + "\nError Info:\n " + \
str(sys.exc_type)+ ": " + str(sys.exc_value) + "\n"
AddPrintMessage(pymsg, 2)
msgs = "ArcPy ERRORS:\n" + arcpy.GetMessages(2) + "\n"
AddPrintMessage(msgs, 2)