Объединение нескольких номеров списков в C # - PullRequest
12 голосов
/ 05 августа 2011

Я ищу элегантное решение для следующей ситуации:

У меня есть класс, который содержит список вроде

class MyClass{ 
...
 public List<SomeOtherClass> SomeOtherClassList {get; set;}
...
}

Третий класс, называемый Model, содержит List<Myclass>, с которым я работаю с extern.

Теперь я хотел бы расширить класс Model с помощью метода, который возвращает все уникальные экземпляры SomeOtherClass для всех экземпляров MyClass.

Я знаю, что есть метод Union(), и с помощью цикла foreach я мог бы легко решить эту проблему, что я и сделал на самом деле. Однако, поскольку я новичок во всех возможностях C # 3 +, мне любопытно, как этого можно добиться более элегантно, с Linq или без него.

Я нашел подход, который мне кажется довольно неуклюжим, но он работает:

        List<SomeOtherClass> ret = new List<SomeOtherClass>();
        MyClassList.Select(b => b.SomeOtherClasses).ToList().ForEach(l => ret = ret.Union(l).ToList()); 
        return ret;

Примечание: свойство b.SomeotherClasses возвращает List<SomeOtherClasses>.

Этот код далек от совершенства, и некоторые вопросы возникают из-за того, что мне нужно выяснить, что такое хороший стиль для работы с C # 3, а что нет. Итак, я составил небольшой список с мыслями об этом фрагменте, и я был бы рад получить несколько комментариев. Кроме того, я был бы рад услышать некоторые комментарии о том, как улучшить этот код.

  • Временный список ret мог бы быть частью подхода в C # 2, может быть, но правильно ли, что я смогу уйти в отставку из этого списка, используя вместо этого цепочку методов? Или я упускаю суть?
  • Действительно ли необходимо использовать промежуточный метод ToList()? Все, что я хочу, - это выполнить дальнейшие действия с каждым участником выбора.
  • Какова стоимость этих операций ToList ()? Это хороший стиль? Необходимая?

Спасибо.

Ответы [ 2 ]

26 голосов
/ 05 августа 2011

Вы ищете SelectMany() + Distinct():

List<SomeOtherClass> ret =  MyClassList.SelectMany( x => x.SomeOtherClasses)
                                       .Distinct()
                                       .ToList();

SelectMany() сведет «список списков» в один список, затем вы можете просто выбрать отдельные записи в этом перечислении вместо использования объединения между отдельными подсписками.

Как правило, вы хотите избежать побочных эффектов с Linq, ваш оригинальный подход заключается в злоупотреблении этим моим изменением ret, которое не является частью запроса.

ToList() требуется, поскольку каждый стандартный оператор запроса возвращает новое перечисление и не изменяет существующее перечисление, поэтому вам необходимо преобразовать окончательный результат перечисления обратно в список. Стоимость ToList() - это полная итерация перечисления, которая в большинстве случаев незначительна. Конечно, если ваш класс может использовать IEnumerable<SomeOtherClass> вместо этого, вам вообще не нужно конвертировать в список.

0 голосов
/ 05 августа 2011

Вы должны взглянуть на SelectMany . Нечто подобное должно сгенерировать ваш «плоский» список:

MyClassList.SelectMany(b => b.SomeOtherClasses)

Возвращает IEnumerable<SomeOtherClass>, который вы можете отфильтровать / обработать далее.

...