如何使用LINQ进行分组&项目对象,基于成员字典键?

时间:2017-12-08 19:11:31

标签: c# list linq dictionary

我有一个List<Predictions>我希望投射到List<List<PredictionObj>>。这两个类定义如下:

public Predictions
{
    public Dictionary<string, double> PredictedMetrics { get; private set; }
    public DateTime PredictionTimeStamp { get; set; }
    public Predictions()
    {
        PredictedMetrics = new Dictionary<string, double>();
    }
}

public class PredictionObj
{
    public string PredictedMetricName { get; set; }
    public double PredictedMetricValue { get; set; }
    public DateTime PredictionTimeStamp { get; set; }
}

对于上下文,Predictions列表中的每个List<Predictions>对象都包含一组指标的预测值集合(PredictedMetrics),这些指标是在PredictionTimeStamp生成的。我想将每个指标分成他们自己的列表,这样列表中的每个唯一List<PredictionObj>键都会有一个列表(PredictedMetrics)。 (PredictedMetricName将映射到字典的键,PredictedMetricValue将映射到字典的值)。我想将所有这些列表存储在一个List<List<PredictionObj>>列表中。

有没有办法使用LINQ扩展方法实现这一目标?

您可以将以下内容复制/粘贴到LINQPad中作为示例。我正在寻找能够完成GenerateSeperateMetricLists正在做的LINQ:

void Main()
{
    DateTime currTime = DateTime.UtcNow;
    List<Predictions> records = new List<Predictions>();
    Predictions record1 = new Predictions();
    record1.PredictedMetrics.Add("metric1", 2.2d);
    record1.PredictedMetrics.Add("metric2", 0.2d);
    record1.PredictionTimeStamp = currTime;
    records.Add(record1);
    Predictions record2 = new Predictions();
    record2.PredictedMetrics.Add("metric1", 1.2d);
    record2.PredictedMetrics.Add("metric2", 0.1d);
    record2.PredictionTimeStamp = currTime.AddMinutes(1);
    records.Add(record2);
    Predictions record3 = new Predictions();
    record3.PredictedMetrics.Add("metric1", 3.2d);
    record3.PredictedMetrics.Add("metric2", 0.3d);
    record3.PredictionTimeStamp = currTime.AddMinutes(2);
    records.Add(record3);
    Predictions record4 = new Predictions();
    record4.PredictedMetrics.Add("metric1", 4.2d);
    record4.PredictedMetrics.Add("metric2", 0.4d);
    record4.PredictionTimeStamp = currTime.AddMinutes(3);
    records.Add(record4);

    //What's the LINQ that could replace this method?
    GenerateSeperateMetricLists(records).Dump();  
}

private static List<List<PredictionObj>> GenerateSeperateMetricLists(List<Predictions> predictionRecords)
{
    var predictionMetricLists = new List<List<PredictionObj>>();
    foreach (Predictions forecastRecord in predictionRecords)
    {
        foreach (KeyValuePair<string, double> prediction in forecastRecord.PredictedMetrics)
        {
            PredictionObj predictionMetric = new PredictionObj
            {
                PredictedMetricName = prediction.Key,
                PredictedMetricValue = prediction.Value,
                PredictionTimeStamp = forecastRecord.PredictionTimeStamp
            };
            var metricList = predictionMetricLists.Where(x => x.First().PredictedMetricName == prediction.Key);
            if (metricList.Count() == 0)
            {
                predictionMetricLists.Add(new List<PredictionObj> {predictionMetric});
            }
            else
            {
                metricList.First().Add(predictionMetric);
            }
        }
    }
    return predictionMetricLists;
}

private class Predictions
{
    public Dictionary<string, double> PredictedMetrics  { get; private set; }
    public DateTime PredictionTimeStamp  { get; set; }
    public Predictions()
    {
        PredictedMetrics = new Dictionary<string, double>();
    }
}

private class PredictionObj
{
    public string PredictedMetricName  { get; set; }
    public double PredictedMetricValue  { get; set; }
    public DateTime PredictionTimeStamp  { get; set; }
}

2 个答案:

答案 0 :(得分:2)

您应首先将数据展平为PredictionObj

列表
var flatList = records
    .SelectMany(r => r.PredictedMetrics.Select(p => new PredictionObj
        {
            PredictedMetricName = p.Key,
            PredictedMetricValue = p.Value,
            PredictionTimeStamp = r.PredictionTimeStamp
        }));

这会生成PredictionObj个对象的平坦序列。现在,您可以按PredictedMetricName

对它们进行分组
flatList.GroupBy(x => x.PredictedMetricName).Dump();

查询语法等效,在一个语句中:

(
    from r in records
    from p in r.PredictedMetrics
    select new PredictionObj
    {
        PredictedMetricName = p.Key,
        PredictedMetricValue = p.Value,
        PredictionTimeStamp = r.PredictionTimeStamp
    } into flatList
    group flatList by flatList.PredictedMetricName into fg
    select fg
).Dump();

答案 1 :(得分:1)

您只需要取出每个Prediction并将其投影到List<PredictionObj>,然后将其转换为List<Prediction>

var ans = records.SelectMany(p => p.PredictedMetrics.Select(pm => new PredictionObj { PredictedMetricName = pm.Key, PredictedMetricValue = pm.Value, PredictionTimeStamp = p.PredictionTimeStamp }))
                 .GroupBy(p => p.PredictedMetricName)
                 .Select(g => g.ToList())
                 .ToList();

已更新OP中的更改。