【问题标题】:LINQ select items from set A which are not in set BLINQ 从集合 A 中选择不在集合 B 中的项目
【发布时间】:2010-07-22 12:52:07
【问题描述】:

我想对一组项目执行例外操作。

代码是这样的:

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

现在,如何从 dataSet.Tables[0] 中选择不在 dgvColumns 中的列? 我知道 DataGridView 中的列与 DataSet 中的列类型不同。我只想选择公共值的一个子集。像这样:

        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 };

上面的代码选择了两个集合中的“列”。所以我坚持我将在 DataSet 中创建另一组“列”:

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

现在我可以表演了,除了这样:

var ColumnsOnlyInDS = ColumnsInDS.Except<ColumnsInDGV>;

但我收到两个错误:

  1. 找不到类型或命名空间名称“ColumnsInDGV”(是否缺少 using 指令或程序集引用?)
  2. 无法将方法组分配给隐式类型的局部变量

因此解决方案是构建一个类,然后使用它而不是隐式类型的局部变量。但我认为仅出于这个原因开发一个类是不必要的开销。

这个问题还有其他解决方案吗?

【问题讨论】:

    标签: c# linq except


    【解决方案1】:

    你几乎得到它。你只需要写:

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

    代替:

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

    更新:因此,上述内容实际上不起作用,因为Except 依赖于比较两个序列中的项目是否相等;显然,您的匿名类型没有覆盖object.Equals,因此您创建的此类型的每个对象都被视为不同的值。试试这个*:

    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);
    

    *注意:上述dsDgvColumns 表达式中的WhereSkipWhile 更有意义,因为它将对所有 结果应用指定的过滤器。 SkipWhile 只会应用过滤器,只要它是真的,然后就会停止应用它。换句话说,如果您的DataGridViewColumn 未绑定到您的DataSet 位于DataGridView开头,它将起作用;但如果它在中间或最后,则不是。

    【讨论】:

    • 谢谢!第一个解决方案不起作用,没有编译器错误,但返回了所有列。第二个解决方案有效,但是在执行 'var dsDgvColumns = dgvColumns.Select(c => dsColumns[c.DataPropertyName]);' dsDgvColumns 中有一个空列。也许原因是我在 DataGridView 中有一列不在 DataSet 中。如何以 dsDgvColumns 不包含空值的方式修改上述查询?
    • 我已经像这样修改它以摆脱空值。我不知道这是否是执行此操作的最佳方法? var dsDgvColumns = dgvColumns.SkipWhile(c => dsColumns[c.DataPropertyName] == null) .Select(c => dsColumns[c.DataPropertyName]);
    • @Wodzu:WhereSkipWhile 更合适。我还想到为什么第一个解决方案不起作用。查看我的编辑。
    • 感谢 Dan 对此感兴趣。我在谷歌上搜索匿名类型和 Equals 并偶然发现了这个问题:stackoverflow.com/questions/543482/…。因此,编译器会自动覆盖匿名类型的 Equals,如果是这样,那么在 except() 方法期间,它应该能够知道两个对象是相同的(每个属性具有相同的属性值),但事实并非如此。任何其他想法为什么?
    猜你喜欢
    • 2019-04-17
    • 1970-01-01
    • 2013-12-21
    • 2016-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多