Лямбда способ заполнить поле значения в методе ToDictionary ()? - PullRequest
4 голосов
/ 25 мая 2009

У меня есть два IEnumerable

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

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

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

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

UPDATE
Обменяется с любым; Решение, которое предлагается чаще всего, было тем, что я попробовал первым, но по какой-то причине оно не было принято:

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

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

Предложения

Отказ от ответственности: имена и код сниффируются, чтобы держать фокус в нужном месте

Ответы [ 4 ]

5 голосов
/ 25 мая 2009

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

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

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

4 голосов
/ 25 мая 2009

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

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

var secondDict = firstDictionary
                 .Where(p => SomeCondition(p))
                 .ToDictionary(p => p.Key, p => p.Value);
1 голос
/ 25 мая 2009

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

Одним из подходов может быть добавление всех предпочтительных объектов в HashSet и использование Contains. Другим может быть использование запроса linq, в котором вы объединяете фактические объекты с предпочтительными объектами, используя соединение с и используете 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);
}
1 голос
/ 25 мая 2009

Ты почти там:

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

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

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

...