Select to view content in your preferred language

Data grouping in ArcObjects

727
0
01-28-2017 09:01 PM
Status: Open
MaxMax2
Frequent Contributor

There are no built-in methods in ArcObjects to perform grouping of rows/features. It is common task in table processing so it is strange to me that this functionality is missed. To implement grouping developers can use at now following approaches:

IQueryFilterDefinition.PostfixClause

IQueryFilter queryFilter = new QueryFilterClass
{
    PostfixClause = "GROUP BY SOME_FIELD"
};

ICursor cursor = table.Search(queryFilter, true);‍‍‍‍‍‍

But:

  1. this works only for GDBs;
  2. you need manually determine where current group ends and starts another one (in other words, you need track changings of field's value while iterating by cursor);
  3. it is unable to perform custom grouping, for example, based on some spatial criteria.

ITableSort

You can sort rows with ITableSort and then iterate through records to form groups. But:

  1. ITableSort has some limitations:
    • it can't be used to sort tables without an ObjectID field;
    • it can't be used to perform custom sorting based on some spatial criteria.
  2. as with first approach you need track changings of field's value while iterating by cursor to determine end of each group.

It would be great if you provide a way to group table data in ArcObjects with following key features:

  1. iterating by groups, so it will be easy to know their bounds;
  2. grouping by multiple fields;
  3. support for shapefiles and tables without an ObjectID field;
  4. ability to use custom grouping logic.

It can be something like that:

public class CustomTableGroup : ITableGroupCallBack
{
    public bool IsNewGroup(int[] fieldIndicies, object[] currentValues, object[] newValues)
    {
        // determine here if passed newValues start a new group 
    }
}

// ...

ITableGroup tableGroup = new TableGroupClass
{
    Table = table,
    Fields = "field1, field2, field3",
    Group = new CustomTableGroup()
};

// ...

IGroupCursor groupCursor = null;

try
{
    groupCursor = tableGroup.Group();

    for (IGroup group; (group = groupCursor.NextGroup()) != null;)
    {
        // indices of the fields to group by

        int[] fieldIndices = group.FieldIndices;

        // values of the fields to group by for the current group

        object[] fieldValues = group.FieldValues;

        // iterate through the group

        ICursor cursor = null;

        try
        {
            cursor = group.Rows;

            for (IRow row; (row = cursor.NextRow()) != null;)
            {
                // do something
            }
        }
        finally
        {
            if (cursor != null)
                Marshal.ReleaseComObject(cursor);
        }
    }
}
finally
{
    if (groupCursor != null)
        Marshal.ReleaseComObject(groupCursor);
}
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍