2016-11-19 2 views
-1

Имея следующие модели (я отправляю интерфейсы для простоты).Объединить 3 разных типа списков в одном новом списке типов

public class LengthViewModel 
{ 
    public int Length { get; set; } 
    public string Category { get; set; } 
} 

public class SlopeViewModel 
{ 
    public int Slope { get; set; } 
    public string Category { get; set; } 
} 

public class RatingViewModel 
{ 
    public double Rating { get; set; } 
    public string Category { get; set; } 
} 

У меня тогда есть в другой ViewModel ObservableCollection каждого типа.

public ObservableCollection<LengthViewModel> Lengths { get; set; } 
public ObservableCollection<SlopeViewModel> Slopes { get; set; } 
public ObservableCollection<RatingViewModel> Ratings { get; set; } 

Мне нужно преобразовать приведенные выше списки в один список, ниже - новый тип списка, который должен быть создан.

public ObservableCollection<LengthSlopeRatingViewModel> Aggregate { get; set; } 

public class LengthSlopeRatingViewModel 
{ 
    public string Category { get; set; } 
    public int Length { get; set; } 
    public int Slope { get; set; } 
    public double Rating { get; set;} 
} 

Что я пробовал до сих пор, но, похоже, задерживается, как выбирать свойства для каждого преобразованного списка.

var lengths = Lengths.Select(p => new LengthSlopeRatingViewModel 
{ 
    Category = p.Category, 
    Length = p.Length 
}); 

var slopes = Slopes.Select(p => new LengthSlopeRatingViewModel 
{ 
    Category = p.Category, 
    Slope = p.Slope 
}); 

var ratings = Ratings.Select(p => new LengthSlopeRatingViewModel 
{ 
    Category = p.Category, 
    Rating = p.Rating 
}); 

// Concat and group them, then select new type again with the properties? 
CourseRatings = lengths.Concat(slopes) 
    .Concat(ratings) 
    .GroupBy(p => p.Category) 
    .Select(g => g.ToList()) 
    .As<IEnumerable<LengthSlopeRatingViewModel>>() 
    .ToObservableCollection(); 

Например, если у вас есть экземпляр с длиной, наклоном и рейтинг и Category = "Black" и другом случае с Category = "Blue" я должен получить два экземпляра LengthSlopeRatingViewModel, один с Category = "Black" и соответствующие значения первого матча и один с Category = "Blue" ,

+0

Не следует ли «Выбрать» после 'GroupBy'' SelectMany'? – KMoussa

+1

Пожалуйста, приложите больше усилий для форматирования кода при задании вопросов - нет необходимости, чтобы большая часть его была отступена далеко вправо. На этот раз я редактирую вопрос. Похоже на то, что вы действительно хотите здесь, это пара объединений, если честно ... вы также должны сказать, что вы хотите, если категория находится только в одной или двух из оригинальных коллекций. –

+0

Я признаю, что для этого нужно немного поработать над вопросом, и теперь я вижу присоединение, я немного застрял, спасибо за редактирование :-) –

ответ

2

Объединение нескольких списков по общему критерию может быть выполнено с использованием join.

Если вы хотите LengthSlopeRatingViewModel результат только тогда, когда все коллекции содержат один соответствующей категории пункт:

Aggregate = new ObservableCollection<LengthSlopeRatingViewModel>(
    from l in Lengths 
    join s in Slopes on l.Category equals s.Category 
    join r in Ratings on s.Category equals r.Category 
    select new LengthSlopeRatingViewModel { 
     Category = l.Category, 
     Length = l.Length, 
     Slope = s.Slope, 
     Rating = r.Rating 
    }); 

Если, например, некоторые рейтинги отсутствуют и вы все еще хотите получить список с рейтингами по умолчанию:

Aggregate = new ObservableCollection<LengthSlopeRatingViewModel>(
    from l in Lengths 
    join s in Slopes on l.Category equals s.Category 
    join r in Ratings on s.Category equals r.Category into ratings 
    from r in ratings.DefaultIfEmpty() 
    select new LengthSlopeRatingViewModel { 
     Category = l.Category, 
     Length = l.Length, 
     Slope = s.Slope, 
     Rating = r?.Rating ?? 0 
    }); 

Бывший эквивалентно:

Aggregate = new ObservableCollection<LengthSlopeRatingViewModel>(
    Lengths 
    .Join(Slopes, _ => _.Category, _ => _.Category, 
     (l, s) => new LengthSlopeRatingViewModel 
      { Category = l.Category, Length = l.Length, Slope = s.Slope }) 
    .Join(Ratings, _ => _.Category, _ => _.Category, 
     (ls, r) => { ls.Rating = r.Rating; return ls; })); 

Они должны быть легко адаптированы к другим потребительных случаях, например, (добавьте DefaultIfEmpty) или пропущенные длины (порядок изменения объединений), если вы не хотите реального полного внешнего соединения, то есть вы ожидаете любых длин, склонов и рейтингов, чтобы не включать категории в другую коллекцию. Затем создается список всех категорий и левые-внешние соединения моделей просмотра:

var categories = 
    Lengths.Select(_ => _.Category).Concat(
    Slopes.Select(_ => _.Category)).Concat(
    Ratings.Select(_ => _.Category)) 
    .Distinct(); 

Aggregate = new ObservableCollection<LengthSlopeRatingViewModel>(
    from c in categories 
    join l in Lengths on c equals l.Category into lengths 
    from l in lengths.DefaultIfEmpty() 
    join s in Slopes on c equals s.Category into slopes 
    from s in slopes.DefaultIfEmpty() 
    join r in Ratings on c equals r.Category into ratings 
    from r in ratings.DefaultIfEmpty() 
    select new LengthSlopeRatingViewModel 
    { 
     Category = c, 
     Length = l?.Length ?? 0, // or any other default 
     Slope = s?.Slope ?? 0, 
     Rating = r?.Rating ?? 0 
    }); 
+0

Спасибо за подробный ответ, именно то, что мне нужно! –