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 <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">new</SPAN> <SPAN class="token class-name">QueryFilterClass</SPAN>
<SPAN class="punctuation token">{</SPAN>
PostfixClause <SPAN class="operator token">=</SPAN> <SPAN class="string token">"GROUP BY SOME_FIELD"</SPAN>
<SPAN class="punctuation token">}</SPAN><SPAN class="punctuation token">;</SPAN>
ICursor cursor <SPAN class="operator token">=</SPAN> table<SPAN class="punctuation token">.</SPAN><SPAN class="token function">Search</SPAN><SPAN class="punctuation token">(</SPAN>queryFilter<SPAN class="punctuation token">,</SPAN> <SPAN class="keyword token">true</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN><SPAN class="line-numbers-rows"><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN></SPAN>But:
- this works only for GDBs;
- 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);
- 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:
- 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.
- 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:
- iterating by groups, so it will be easy to know their bounds;
- grouping by multiple fields;
- support for shapefiles and tables without an ObjectID field;
- ability to use custom grouping logic.
It can be something like that:
<SPAN class="keyword token">public</SPAN> <SPAN class="keyword token">class</SPAN> <SPAN class="token class-name">CustomTableGroup</SPAN> <SPAN class="punctuation token">:</SPAN> ITableGroupCallBack
<SPAN class="punctuation token">{</SPAN>
<SPAN class="keyword token">public</SPAN> <SPAN class="keyword token">bool</SPAN> <SPAN class="token function">IsNewGroup</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="keyword token">int</SPAN><SPAN class="punctuation token">[</SPAN><SPAN class="punctuation token">]</SPAN> fieldIndicies<SPAN class="punctuation token">,</SPAN> <SPAN class="keyword token">object</SPAN><SPAN class="punctuation token">[</SPAN><SPAN class="punctuation token">]</SPAN> currentValues<SPAN class="punctuation token">,</SPAN> <SPAN class="keyword token">object</SPAN><SPAN class="punctuation token">[</SPAN><SPAN class="punctuation token">]</SPAN> newValues<SPAN class="punctuation token">)</SPAN>
<SPAN class="punctuation token">{</SPAN>
<SPAN class="comment token">// determine here if passed newValues start a new group </SPAN>
<SPAN class="punctuation token">}</SPAN>
<SPAN class="punctuation token">}</SPAN>
<SPAN class="comment token">// ...</SPAN>
ITableGroup tableGroup <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">new</SPAN> <SPAN class="token class-name">TableGroupClass</SPAN>
<SPAN class="punctuation token">{</SPAN>
Table <SPAN class="operator token">=</SPAN> table<SPAN class="punctuation token">,</SPAN>
Fields <SPAN class="operator token">=</SPAN> <SPAN class="string token">"field1, field2, field3"</SPAN><SPAN class="punctuation token">,</SPAN>
Group <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">new</SPAN> <SPAN class="token class-name">CustomTableGroup</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN>
<SPAN class="punctuation token">}</SPAN><SPAN class="punctuation token">;</SPAN>
<SPAN class="comment token">// ...</SPAN>
IGroupCursor groupCursor <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">null</SPAN><SPAN class="punctuation token">;</SPAN>
<SPAN class="keyword token">try</SPAN>
<SPAN class="punctuation token">{</SPAN>
groupCursor <SPAN class="operator token">=</SPAN> tableGroup<SPAN class="punctuation token">.</SPAN><SPAN class="token function">Group</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN>
<SPAN class="keyword token">for</SPAN> <SPAN class="punctuation token">(</SPAN>IGroup <SPAN class="keyword token">group</SPAN><SPAN class="punctuation token">;</SPAN> <SPAN class="punctuation token">(</SPAN><SPAN class="keyword token">group</SPAN> <SPAN class="operator token">=</SPAN> groupCursor<SPAN class="punctuation token">.</SPAN><SPAN class="token function">NextGroup</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN> <SPAN class="operator token">!=</SPAN> <SPAN class="keyword token">null</SPAN><SPAN class="punctuation token">;</SPAN><SPAN class="punctuation token">)</SPAN>
<SPAN class="punctuation token">{</SPAN>
<SPAN class="comment token">// indices of the fields to group by</SPAN>
<SPAN class="keyword token">int</SPAN><SPAN class="punctuation token">[</SPAN><SPAN class="punctuation token">]</SPAN> fieldIndices <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">group</SPAN><SPAN class="punctuation token">.</SPAN>FieldIndices<SPAN class="punctuation token">;</SPAN>
<SPAN class="comment token">// values of the fields to group by for the current group</SPAN>
<SPAN class="keyword token">object</SPAN><SPAN class="punctuation token">[</SPAN><SPAN class="punctuation token">]</SPAN> fieldValues <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">group</SPAN><SPAN class="punctuation token">.</SPAN>FieldValues<SPAN class="punctuation token">;</SPAN>
<SPAN class="comment token">// iterate through the group</SPAN>
ICursor cursor <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">null</SPAN><SPAN class="punctuation token">;</SPAN>
<SPAN class="keyword token">try</SPAN>
<SPAN class="punctuation token">{</SPAN>
cursor <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">group</SPAN><SPAN class="punctuation token">.</SPAN>Rows<SPAN class="punctuation token">;</SPAN>
<SPAN class="keyword token">for</SPAN> <SPAN class="punctuation token">(</SPAN>IRow row<SPAN class="punctuation token">;</SPAN> <SPAN class="punctuation token">(</SPAN>row <SPAN class="operator token">=</SPAN> cursor<SPAN class="punctuation token">.</SPAN><SPAN class="token function">NextRow</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN> <SPAN class="operator token">!=</SPAN> <SPAN class="keyword token">null</SPAN><SPAN class="punctuation token">;</SPAN><SPAN class="punctuation token">)</SPAN>
<SPAN class="punctuation token">{</SPAN>
<SPAN class="comment token">// do something</SPAN>
<SPAN class="punctuation token">}</SPAN>
<SPAN class="punctuation token">}</SPAN>
<SPAN class="keyword token">finally</SPAN>
<SPAN class="punctuation token">{</SPAN>
<SPAN class="keyword token">if</SPAN> <SPAN class="punctuation token">(</SPAN>cursor <SPAN class="operator token">!=</SPAN> <SPAN class="keyword token">null</SPAN><SPAN class="punctuation token">)</SPAN>
Marshal<SPAN class="punctuation token">.</SPAN><SPAN class="token function">ReleaseComObject</SPAN><SPAN class="punctuation token">(</SPAN>cursor<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN>
<SPAN class="punctuation token">}</SPAN>
<SPAN class="punctuation token">}</SPAN>
<SPAN class="punctuation token">}</SPAN>
<SPAN class="keyword token">finally</SPAN>
<SPAN class="punctuation token">{</SPAN>
<SPAN class="keyword token">if</SPAN> <SPAN class="punctuation token">(</SPAN>groupCursor <SPAN class="operator token">!=</SPAN> <SPAN class="keyword token">null</SPAN><SPAN class="punctuation token">)</SPAN>
Marshal<SPAN class="punctuation token">.</SPAN><SPAN class="token function">ReleaseComObject</SPAN><SPAN class="punctuation token">(</SPAN>groupCursor<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN>
<SPAN class="punctuation token">}</SPAN>
<SPAN class="line-numbers-rows"><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN></SPAN>