将 3 个不同类型的列表合并为一个新的列表类型

Merge 3 different type lists in one new list type

具有以下模型(为简单起见,我发布了界面)。

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;}
}

到目前为止我已经尝试过但似乎卡住了如何 select 每个转换列表的属性。

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".

的对应值

可以使用 joins 将多个列表按共同标准合并。

如果您只想要 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)或缺少长度(更改连接顺序),除非您想要真正的完整外部连接,即您 期望 any 长度,斜率和评级不包含另一个集合中存在的类别。然后创建所有类别的列表并左外连接视图模型:

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
    });