Linq检查所有集合是否至少有一个公共项目

时间:2014-01-31 11:25:27

标签: c#-4.0 linq-to-objects

我正在研究一些代码并掌握这个概念,但我不确定如何在LINQ-to-objects中表达它。

我的情景是:

  

具有分层数据的树,可以使用拖放操作将某些项重新定位到其他父项。

我想支持拖动多个项目,树的示例如下:

  • 周期
    • 实例
  • 周期
    • 实例

层次结构中的每个视图模型项都是从我公开IReadOnlyList<Type>的基本类型派生出来的,该基类型表明每个层次结构项目很乐意被重新定位为子项。

PreviewDragEnter事件中,我已经检查过每个被拖动的项目实际上都支持重新定位。

我实际想要解决的问题是如何检查每个至少1种类型的readonly列表,以便我可以确定每个被拖动的项目都可以重新定位到同一目标。

我意识到如果我从一个集合转到下一个集合,可以进行1-1 .Any()检查,但是如何为任意数字执行此操作?

到目前为止,我有类似的东西,但我不确定它是否正确,它看起来不是最佳:

private void RadTreeView_PreviewDragStarted(object sender, Telerik.Windows.Controls.RadTreeViewDragEventArgs e)
{
    var items = e.DraggedItems.Cast<HierarchyItemViewModel>();

    // Every item being dragged must support being dragged
    if (items.Any(i => i.ValidReorgTargets.Count == 0))
    {
        e.Handled = true;
        return;
    }

    if (items.All(i => HasOneTypeInCommonWithOthers(i, items.Except(new[] { i }))))
    {
        e.Handled = true;
        return;
    }
}

private bool HasOneTypeInCommonWithOthers(HierarchyItemViewModel item, IEnumerable<HierarchyItemViewModel> others)
{
    return others.All(i => i.ValidReorgTargets.Intersect(item.ValidReorgTargets).Any());
}

任何比这更好的东西都会非常感激。

2 个答案:

答案 0 :(得分:1)

这应该有效:

if (items.Select(i => i.ValidReorgTargets).Aggregate((i1, i2) => i1.Intersect(i2)).Any())
{
    e.Handled = true;
    return;
}

换句话说,如果所有ValidReorgTargets个集合中都有一个共同的交集,那么它们可以重新定位到同一个目标。

答案 1 :(得分:0)

(我本来会给你编译可编码的代码,但我不确定你的例子中的内容是什么,你将术语从实例更改为视图模型项到基类型到层次结构类型,只读列表到HierarchyViewItemModel和所以,只需按照文字说出来。)

枚举每个只读列表中的每个类型,累积到Dictionary&lt; type,int&gt;找到的每种类型的实例数。假设任何只读列表中没有重复项(您可以使用Distinct删除),那么字典中所有元素的键(其中累计值是您开始使用的只读列表的数量)就是您想要的类型。

累积字典是O(n),其中n是要添加到字典中的所有只读列表中的类型总数(从MSDN我们了解到Dictionary.Add是分摊的O(1)...或者可以是如果你在扩展字典时要小心一些),确定有值==你的只读列表数的类型(键)的数量是O(m),其中m是所有只读列表中不同类型的数量。因此,该算法在您的只读列表的所有元素的总大小上是线性的。