Подтвердить что ты не робот

Объединение нескольких списков в С#

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

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

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

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

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

Я знаю, что существует метод Union() и с циклом foreach я могу легко решить эту проблему, что я и сделал. Однако, поскольку я новичок во всех функциях С# 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 возвращает a List<SomeOtherClasses>.

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

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

Спасибо.

4b9b3361

Ответ 1

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

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

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

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

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

Ответ 2

Вы должны посмотреть SelectMany. Что-то вроде этого должно генерировать ваш "плоский" список:

MyClassList.SelectMany(b => b.SomeOtherClasses)

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