2009-05-25 1 views
3

У меня есть два IEnumerableLambda способ заполнить поле значения в методе ToDictionary()?

IEnumerable<MyObject> allowedObjects = MyService.GetAllowedObjects(); 
IEnumerable<MyOBject> preferedObjects = MyService.GetPreferedObjects(); 

Мы можем с уверенностью предположить, что preferedObjects всегда будет подмножеством allowedObjects.
Я хочу создать IDictionary<MyObject, bool>. Объекты, где ключ - это набор MyObjects из разрешенных объектов, а bool - true, если экземпляр MyObject также был указан в списке предпочтительных объектов.

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

IDictionary<MyObject, bool> selectedObjects = allowedObjects 
    .ToDictionary(o => new KeyValuePair<MyObject, bool>() 
     { Key = q, 
      Value = preferedObjects.Any(q) 
     } 
    ); 

UPDATE
Exchanged Содержит с Любой; Решение, которое предлагается больше всего то, что я пытался первым, но это не принято по некоторым причинам:

IDictionary<MyObject, bool> selectedObjects = allowedObjects 
    .ToDictionary<MyObject, bool>(o => o, preferedObjects.Any(o)); 

Visual Studio говорит первый метод не возвращает логическое значение. Это правда, но главным образом потому, что bool не будет правильным результатом, чтобы начать с ...
И тогда он говорит, что не может вывести тип второй лямбда ...
Как вы можете видеть, я попытался явно определить типы, которые помогут сделать вывод, но это не решает ничего.

Предложения?

Отказ от ответственности: имена и код snippyfied держать в центре внимания, где она должна быть

+0

Вы не определяете второй параметр как выражение лямбда! Добавьте бит 'o =>' before 'preferedObjects.Any (o)', и он должен работать нормально (без необходимости указывать общие типы или использовать 'Any', а не' Contains'). – Noldorin

ответ

4

Я не могу вспомнить, обеспечивает ли Linq «вхождения» метод расширения на IEnumerable<T>. Если нет, то вы можете использовать любой:

var dict = allowedObjects.ToDictionary(o => o, 
    o => preferredObjects.Contains(o)); 

** Редактировать ** Да, просто проверял это и есть действительно метод расширения Содержит(), так что приведенный выше код работает.

+0

Bizar, вот этот синтаксис кажется не работает: Мой реальный код: Dictionary <Качество, BOOL> selectedQualities = allowedQualities .ToDictionary <Качество, BOOL> (к => к, v => preferedQualities.Any (v)); С первым q VS говорит, что он не может преобразовать мое качество в bool; Вторая лямбда (v) говорит, что не может вывести тип ... –

+0

Ну, это странно. Я тестировал пару переменных IEnumerable , поэтому, возможно, использование класса качества смущает компилятор. –

+0

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

2

Enumerable.ToDictionary имеет несколько перегрузок. Некоторые из них принимают второго делегата (так что вы можете передать лямбда), чтобы вернуть значение, которое нужно использовать с ключом.

Что-то вроде:

var secondDict = firstDictionary 
       .Where(p => SomeCondition(p)) 
       .ToDictionary(p => p.Key, p => p.Value); 
1

Вы почти там:

IDictionary<MyObject, bool> selectedObjects = allowedObjects 
    .ToDictionary(o => o, o => preferedObjects.Contains(q)); 

Метод расширения ToDictionary работает вокруг, используя два лямбда-выражения для создания пары ключ/значение, а не KeyValuePair типа.

Вы можете быстро изменить ситуацию, используя HashSet<T> объектов для своих коллекций allowedObjects и preferredObjects, хотя я бы не стал беспокоиться, если ваши списки особенно значительны/важны.

+0

Пожалуйста, смотрите OP для получения дополнительной информации о проблеме с вашим предложением. Списки невелики и исходят из службы, которая возвращает IEnumerables, поэтому я действительно могу вылить их в HashSet, но я не думаю, что это действительно будет метод, который замедлит мой код;) –

+0

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

+0

@Boris: Да, никогда не оптимизируйте преждевременно, на самом деле. Как вы говорите, если оставить их как простые IEnumerables, это не проблема. – Noldorin

1

Вы можете, конечно, создать свой собственный метод расширения. ToDictionary просто создает словарь, добавляя все элементы в источнике как значения и используя lambda как ключ. Вы можете создать свой собственный с другим подходом.Поскольку вы используете «contains», я не думаю, что это хорошая идея сделать это таким образом, поскольку это медленная операция (линейный поиск для каждого элемента в allowedObjects, вы перечисляете предпочтительные объекты).

Один из подходов может заключаться в том, чтобы добавить все предпочтительные объекты в HashSet и использовать для этого Содержит. Другим может быть использование запроса linq, в котором вы присоединяетесь к actualObjects с preferredObjects, используя join и используете DefaultIfEmpty. Это более эффективно:

List<MyObject> allowedObjects = new List<MyObject>() { new MyObject("one"), new MyObject("two"), new MyObject("three")}; 
List<MyObject> preferredObjects = allowedObjects.Take(2).ToList(); 

var q = from a in allowedObjects 
     join p in preferredObjects on a equals p into ap 
     from x in ap.DefaultIfEmpty() 
     let isPreferred = (x != null) 
     let toUse = x ?? a 
     select new { toUse, isPreferred }; 

Dictionary<MyObject, bool> selectedObjects = new Dictionary<MyObject, bool>(); 
foreach(var v in q) 
{ 
    selectedObjects.Add(v.toUse, v.isPreferred); 

    Console.WriteLine("{0}, {1}", v.toUse.Foo, v.isPreferred); 
} 
+0

Хотя это действительно не отвечает на мой вопрос, здесь есть полезная информация. Не принято еще повышать :) Thx –

+0

Спасибо, хотя я думаю, что он отвечает на ваш вопрос или лучше: он отвечает на основной вопрос: как получить словарь, который вы хотите;). (поскольку здесь важнее ИМХО, чем здесь). –