2014-01-31 2 views
0

В настоящий момент я немного разбираюсь в коде, и я понимаю концепцию, но я не уверен, как бы я выразился в LINQ-to -объекты.Linq проверяет, есть ли у всех коллекций хотя бы один общий элемент.

Сценарий у меня есть это:

Дерево с иерархическими данными, в результате чего некоторые элементы может быть перемещены с помощью перетаскивания для других родительских элементов.

Я хочу поддержать несколько элементов тащат, пример дерева выглядит следующим образом:

  • Период
    • Instance
  • Период
    • Instance

Каждый вид элементов модели в иерархии происходит от базового типа, на котором я обнажая в IReadOnlyList<Type>, которая гласит, какие типы иерархии каждая иерархия элемент счастлив быть переведен как ребенок.

На мероприятии PreviewDragEnter Я уже проверяю, что каждый перетаскиваемый элемент фактически поддерживает перемещение.

Проблема, которую я действительно хочу решить, - это проверить каждый из этих списков только для чтения по крайней мере для одного типа, чтобы я мог быть уверен, что каждый перемещаемый элемент может быть перенесен на одну и ту же цель.

Я понимаю, что проверка 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()); 
} 

Все лучше, чем это было бы весьма признателен.

ответ

1

Это должно работать:

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

Другими словами, если есть общее пересечение по всем ValidReorgTargets коллекции, то они могут быть перемещены к одной и той же цели.

0

(я бы дал вам компилируемый код, но я не совсем уверен, что происходит в вашем примере, когда вы меняете терминологию с экземпляра, чтобы просмотреть элемент модели базовому типу для типа иерархии для списков только для чтения в HierarchyViewItemModel и т. д. Итак, следуют только слова.)

Перечислите каждый тип в каждом из ваших списков только для чтения, скопив в словарь < тип, int > Число экземпляров каждого найденного типа. Если не считать дубликатов в любом списке только для чтения (который вы можете удалить с помощью Distinct), то ключи всех элементов в вашем словаре, где накопленное значение - это количество списков только для чтения, с которыми вы начали, - это те типы, которые вы хотите.

Накопительный словарь - это O (n), где n - общее количество типов во всех списках readonly для добавления в словарь (из MSDN мы узнаем, что Dictionary.Add амортизируется O (1) ... или может если вы проявляете особую осторожность при расширении Словаря), определяя количество типов (ключей), которые имеют значение ==, число ваших списков только для чтения равно O (m), где m - количество различных типов во всех списках только для чтения.Таким образом, алгоритм является линейным в общем размере всех элементов ваших списков только для чтения.

Смежные вопросы