tags:

views:

84

answers:

1

I would like to perform an Except operation on set of items.

Code is like this:

IEnumerable<DataGridViewColumn> dgvColumns = dataGridView.Columns.OfType<DataGridViewColumn>();
IEnumerable<DataColumn> dsColumns = dataSet.Tables[0].Columns.OfType<DataColumn>();

Now, how to select Columns from dataSet.Tables[0] which are not in dgvColumns? I know that Columns from DataGridView are different type than Columns in DataSet. I want to pick up only a subset of common values. Like this:

        var ColumnsInDGV = from c1 in dgvColumns
                           join c2 in dsColumns on c1.DataPropertyName equals c2.ColumnName
                           select new { c1.HeaderText, c1.DataPropertyName, c2.DataType, c1.Visible };

Above code selects me "columns" that are in both sets. So I tought I will create another set of "columns" that are in DataSet:

  var ColumnsInDS = from c2 in dsColumns select new { HeaderText = c2.ColumnName, DataPropertyName = c2.ColumnName, c2.DataType, Visible = false };

and now that I will be able to perfrom Except like this:

var ColumnsOnlyInDS = ColumnsInDS.Except<ColumnsInDGV>;

But I am getting two errors:

  1. The type or namespace name 'ColumnsInDGV' could not be found (are you missing a using directive or an assembly reference?)
  2. Cannot assign method group to an implicitly-typed local variable

So the solution would be to build a class and then use it instead of implictly - typed local variable. But I think that developing a class only for this reason is a not necessery overhead.

Is there any other solution for this problem?

+2  A: 

You've almost got it. You just need to write:

// use () to pass a parameter
// type (should) be inferred
var ColumnsOnlyInDS = ColumnsInDS.Except(ColumnsInDGV);

instead of:

// do not use <> - that passes a type parameter;
// ColumnsInDGV is not a type
var ColumnsOnlyInDS = ColumnsInDS.Except<ColumnsInDGV>;

Update: So, the above actually doesn't work because Except depends on comparing items in two sequences for equality; obviously, your anonymous type has not overriden object.Equals and so each object that you create of this type is treated as a distinct value. Try this* instead:

var dgvColumns = dataGridView.Columns.Cast<DataGridViewColumn>();
var dsColumns = dataSet.Tables[0].Columns;

// This will give you an IEnumerable<DataColumn>
var dsDgvColumns = dgvColumns
    .Where(c => dsColumns.Contains(c.DataPropertyName))
    .Select(c => dsColumns[c.DataPropertyName]);

// Then you can do this
var columnsOnlyInDs = dsColumns.Cast<DataColumn>().Except(dsDgvColumn);

*Note: Where in the above expression for dsDgvColumns makes more sense than SkipWhile because it will apply the specified filter over all results. SkipWhile would only apply the filter as long as it was true and would then stop applying it. In other words it would work if your DataGridViewColumn not bound to your DataSet were at the beginning of the DataGridView; but not if it were in the middle or at the end.

Dan Tao
Thanks! The first solution did not work, no compiler error but has returned all the columns. The second solution worked, hovewer after performing 'var dsDgvColumns = dgvColumns.Select(c => dsColumns[c.DataPropertyName]);' there is one null Column in dsDgvColumns. Perhaps the reason is that I have one column in DataGridView which is not in DataSet. How to modify the above query in a way that dsDgvColumns doesn't containt nulls?
Wodzu
I've modified it like this to get rid of nulls. I dont know if this the optimal method to do this?var dsDgvColumns = dgvColumns.SkipWhile(c => dsColumns[c.DataPropertyName] == null) .Select(c => dsColumns[c.DataPropertyName]);
Wodzu
@Wodzu: `Where` would be more appropriate than `SkipWhile`. Also it occurred to me why the first solution didn't work. See my edit.
Dan Tao
Thank you Dan for your interest in this. I was googling for anonymous types and Equals and stumbled upon this question: http://stackoverflow.com/questions/543482/linq-select-distinct-with-anonymous-types . So it seams that compiler automaticaly overrides Equals for anonymous types, if so then during the Except() method it should be able to know that two objects are the same (have the same propery values for each property) but it doesn't. Any other idea why?
Wodzu