我有下面的课程指定数据记录
class DataRecord
{
public double MeasuredValue { get; set; }
public DateTime MeasurementDate { get; set; }
}
我想选择在一小时(日期无所谓)范围内记录的记录,其中记录的数量最大。
示例:
预期输出: 1、4、5 (因为在10:50-11:50范围内进行了3次测量)
我想到的代码是
List<DataRecord> records = new List<DataRecord>();
var maxRecordsInAnHour = records.GroupBy(x => x.MeasurementDate.Hour)
.Aggregate((g1, g2) => { return g2.Count() > g1.Count() ? g2 : g1; });
当我按Hour
属性分组时,此代码返回 2和3 或 1和5 (取决于顺序),并仅使用Hour
中的相同值被分组。
如何调整代码以获得预期的输出?
答案 0 :(得分:1)
我将针对您的问题提出2种解决方案,具体取决于列表的长度。
初始化:
var myList = new List<DataRecord>
{
new DataRecord
{
MeasurementDate = new DateTime(2019, 1, 31, 11, 50, 0)
},
new DataRecord
{
MeasurementDate = new DateTime(2019, 1, 31, 17, 21, 0)
},
new DataRecord
{
MeasurementDate = new DateTime(2019, 1, 31, 17, 59, 0)
},
new DataRecord
{
MeasurementDate = new DateTime(2019, 1, 31, 10, 54, 0)
},
new DataRecord
{
MeasurementDate = new DateTime(2019, 1, 31, 11, 54, 0)
},
};
List<DataRecord> result = new List<DataRecord>();
解决方案1:
var minimumMinutes = myList.Min(x => x.MeasurementDate.Hour * 60 + x.MeasurementDate.Minute);
var maximumMinutes = myList.Max(x => x.MeasurementDate.Hour * 60 + x.MeasurementDate.Minute);
for (int minutes = minimumMinutes; minutes < maximumMinutes; minutes++)
{
var list = myList.Where(x =>
x.MeasurementDate.Hour * 60 + x.MeasurementDate.Minute <= minutes + 60 &&
x.MeasurementDate.Hour * 60 + x.MeasurementDate.Minute >= minutes);
if (result.Count < list.Count())
{
result = list.ToList();
}
}
解决方案2:
foreach (var dataRecord in myList)
{
var minutes = dataRecord.MeasurementDate.Hour * 60 + dataRecord.MeasurementDate.Minute;
var before = myList.Where(x =>
x.MeasurementDate.Hour * 60 + x.MeasurementDate.Minute >= minutes - 60 &&
x.MeasurementDate.Hour * 60 + x.MeasurementDate.Minute <= minutes).ToList();
var after = myList.Where(x =>
x.MeasurementDate.Hour * 60 + x.MeasurementDate.Minute <= minutes + 60 &&
x.MeasurementDate.Hour * 60 + x.MeasurementDate.Minute >= minutes).ToList();
if (before.Count > result.Count ||
after.Count > result.Count)
{
result = before.Count > after.Count ? before.ToList() : after.ToList();
}
}
答案 1 :(得分:1)
正如我在评论中提到的那样,此代码的性能不高,但这可以解决问题。
// DummyData
List<DateTime> dates = new List<DateTime>
{
DateTime.Parse("2019/01/31 11:50"),
DateTime.Parse("2019/02/02 17:21"),
DateTime.Parse("2019/03/01 17:59"),
DateTime.Parse("2019/03/12 10:54"),
DateTime.Parse("2019/05/28 11:15"),
};
// Storage for final Output
List<DateTime> finalOp = new List<DateTime>();
// Main logic goes here
// foreach Hour in list we will compare that with every other Hour in list
// and it is in 1 hour range we will add it to list
foreach (DateTime dateTime in dates)
{
List<DateTime> temp = new List<DateTime>();
foreach (DateTime innerDateTime in dates)
{
// find the difference between two hours
var timeSpan = dateTime.TimeOfDay - innerDateTime.TimeOfDay;
// add it to same list if we have +/- 1 Hour difference
if (timeSpan.TotalHours <= 1 && timeSpan.TotalHours >= -1)
{
temp.Add(innerDateTime);
}
}
// once we have final group for date we will check if this has maximum number of common dates around
// if so replace it with previous choice
if (finalOp.Count < temp.Count)
{
finalOp = temp;
}
}
// print the results
foreach (var data in finalOp)
{
Console.WriteLine(data.ToShortTimeString());
}
答案 2 :(得分:0)
对于myList
集合中的10,000个项目,此解决方案可以很快:
private static List<DataRecord> Get(List<DataRecord> myList)
{
var ordered = myList.OrderBy(x => x.MeasurementDate.TimeOfDay).ToList();
int i = 0;
int count = myList.Count();
var temp =
(from s in ordered
let index = ++i
let next = ordered.ElementAtOrDefault(index != count ? index : 0)
select new
{
Cur = s.MeasurementDate,
Diff = index != count
? (next.MeasurementDate.TimeOfDay - s.MeasurementDate.TimeOfDay).TotalMinutes
: 24 * 60 - (ordered.ElementAtOrDefault(count - 1).MeasurementDate.TimeOfDay - ordered.ElementAtOrDefault(0).MeasurementDate.TimeOfDay).TotalMinutes
}).ToList();
Dictionary<int, int> dict = new Dictionary<int, int>();
count = 0;
double minutes = 0;
for (int index = 0; index < temp.Count(); index++)
{
for (int j = index; j < temp.Count(); j++)
{
minutes += temp[j].Diff;
if (minutes > 60)
{
dict.Add(index, count);
count = 0;
minutes = 0;
break;
}
else
{
count++;
}
}
}
var max = dict.First(d => d.Value == dict.Values.Max());
var finalResult = ordered.Skip(max.Key).Take(max.Value + 1).ToList();
return finalResult;
}
请注意,它会返回有序结果。