Выбор LINQ, отличный от 4 списков IEnumerable

Представьте себе четыре списка, каждый из которых, по крайней мере, имеет это строковое свойство Id, но может иметь и другие свойства:

public class A //or B, C, D
{
    public string Id { get; set; }
    //..other properties
}

//so:  
List<A> a1 = new List<A>();
List<B> a2 = new List<B>();
List<C> a3 = new List<C>();
List<D> a4 = new List<D>();

Я хочу выбрать все идентификаторы DISTINCT в: a1 в сочетании с a2, a3 и a4

Я думал, что синтаксис LINQ был бы идеальным, но как объединить их в результат IEnumerable с одним строковым свойством, например, с определением класса A.


person CRice    schedule 09.06.2009    source источник


Ответы (5)


Действительно ли все списки одного типа? Или у вас есть

List<A> a1 = new List<A>();
List<B> a2 = new List<B>();
List<C> a3 = new List<C>();
List<D> a4 = new List<D>();

и вы хотите объединить их, потому что все 4 типа имеют общее строковое свойство Id?

Хорошо, ваше редактирование показывает, что я был на правильном пути. Вам нужен интерфейс, который определяет свойство строки Id, и каждый тип A, B, C и D должен реализовать этот интерфейс.

Тогда каждый список будет иметь тип интерфейса, и ответы concat будут работать.

Если у вас нет возможности определить интерфейс, вы можете использовать LINQ для запроса каждого списка только для поля Id (вы должны получить IQueryable<String> результатов), а затем объединить эти результаты.

Изменить: вот запрос LINQ, который должен дать вам то, что вы ищете:

var uniqueIds = (from a in a1
                 select a.Id).Concat(
                 from b in a2
                 select b.Id).Concat(
                 from c in a3
                 select c.Id).Concat(
                 from d in a4
                 select d.Id).Distinct();
person CoderDennis    schedule 09.06.2009

Поскольку это разные типы, я бы сначала выбрал свойство Id, чтобы получить IEnumerable‹string›, а затем объединил результаты:

var query = a1.Select(a=> a.Id)
              .Concat(a2.Select(b=> b.Id))
              .Concat(a3.Select(c=> c.Id))
              .Concat(a4.Select(d=> d.Id))
              .Distinct();
person Christian C. Salvadó    schedule 09.06.2009
comment
Точно такой же результат, к которому я наконец пришел. В первой версии вопроса не было совершенно ясно, что это разные типы. - person CoderDennis; 09.06.2009

Это также работает:

new[] {a1, a2, a3, a4}.SelectMany(x => x.Select(y => y.Id)).Distinct();
person idursun    schedule 09.06.2009
comment
Поскольку a1, a2, a3 и a4 являются разными типами, не будет лучшего совпадения типов для неявно типизированного массива... Ошибка компилятора CS0826 (is.gd/Udlw) - person Christian C. Salvadó; 09.06.2009
comment
После моего ответа выяснилось, что a1, a2, a3 и a4 могут иметь разные типы. - person idursun; 09.06.2009

Союз

Конечно, вы можете упростить это:

var uniqueIds = (from a in a1
                 select a.Id).Concat(
                 from b in a2
                 select b.Id).Concat(
                 from c in a3
                 select c.Id).Concat(
                 from d in a4
                 select d.Id).Distinct();

Используя Union (который делает неявный «Distinct»), чтобы стать:

var uniqueIds =  (from a in a1
                 select a.Id).Union(
                 from b in a2
                 select b.Id).Union(
                 from c in a3
                 select c.Id).Union(
                 from d in a4
                 select d.Id);
person Don Gillis    schedule 13.06.2009

Вы можете объединить IEnumerables одного типа, а затем выбрать нужный элемент.

var query = a1
    .Concat(a2)
    .Concat(a3)
    .Concat(a4)
    .Select(a => a.ID)
    .Distinct();

РЕДАКТИРОВАТЬ: На основе нового вопроса... Выбор из разных типов списков невозможен в одном запросе. Лучший способ сделать это — иметь общий тип, включающий выбранное свойство, а затем выполнить приведенный выше запрос с базовым типом.

person Cameron MacFarland    schedule 09.06.2009