在一个新列表类型中合并3个不同类型的列表

时间:2016-11-19 14:30:53

标签: c# linq concat

拥有以下模型(为了简单起见,我发布了接口)。

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"

1 个答案:

答案 0 :(得分:2)

可以使用join s。

按照通用条件组合多个列表

如果您只想在所有馆藏一个相应类别项目时获得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
    });
相关问题