public static IList <long> In(this ITable table, ITable table2, int column1, int column2) { // First pick the the smallest and largest table. We only want to iterate // through the smallest table. // NOTE: This optimisation can't be performed for the 'not_in' command. ITable smallTable; ITable largeTable; int smallColumn; int largeColumn; if (table.RowCount < table2.RowCount) { smallTable = table; largeTable = table2; smallColumn = column1; largeColumn = column2; } else { smallTable = table2; largeTable = table; smallColumn = column2; largeColumn = column1; } // Iterate through the small table's column. If we can find identical // cells in the large table's column, then we should include the row in our // final result. BlockIndex <long> resultRows = new BlockIndex <long>(); IEnumerator <long> e = smallTable.GetRowEnumerator(); Operator op = Operator.Equal; while (e.MoveNext()) { long smallRowIndex = e.Current; DataObject cell = smallTable.GetValue(smallColumn, smallRowIndex); IEnumerable <long> selectedSet = largeTable.SelectRows(largeColumn, op, cell); // We've found cells that are IN both columns, if (selectedSet.Any()) { // If the large table is what our result table will be based on, append // the rows selected to our result set. Otherwise add the index of // our small table. This only works because we are performing an // EQUALS operation. if (largeTable == table) { // Only allow unique rows into the table set. foreach (var set in selectedSet) { if (!resultRows.UniqueInsertSort((int)set)) { break; } } } else { // Don't bother adding in sorted order because it's not important. resultRows.Add((int)smallRowIndex); } } } return(resultRows.Cast <long>().ToList()); }