我问过this之前的问题。这个想法是一样的,只是我必须在特定的 TimeSpan
中找到所有的公共(public)时间。
背景
假设,
我想见一些人,我说我想见日期时间 X(2014-02-16 09:00:00.000) 到日期时间 Y(2014-02-26 05:00:00.000) 之间的某些人。我说我希望 session 至少持续 N
小时。
然后我想见的人会回复说我将在以下日期有空:
Date1(Certain date from certain start time to certain end time),
Date2(certain date from certain time to certain time),
...
等等。
目标
然后我必须查找是否存在包含在所有用户响应中的时间范围。
让我们考虑这些是响应
Attendee1
(Some GuidId):Response1: Start Time=2014-02-23 09:00 AM, EndTime = 2014-02-23 11:00 AM,
Response2 : Start Time=2014-02-24 10:00 AM, EndTime = 2014-02-24 12:00 PM,
Response3 : Start Time=2014-02-25 10:00 AM, EndTime = 2014-02-25 11:00 AM,
Response4 : Start Time=2014-02-23 01:00 PM, EndTime = 2014-02-17 5:00 PM
Attendee2
(Some GuidId):Response1: Start Time=2014-02-22 09:00 AM, EndTime = 2014-02-22 05:00 PM,
Response2 : Start Time=2014-02-23 09:00 AM, EndTime = 2014-02-23 05:00 PM,
Response3 : Start Time=2014-02-25 09:00 AM, EndTime = 2014-02-25 12:00 PM,
Attendee3
(Some GuidId):Response1: Start Time=2014-02-22 11:00 AM, EndTime = 2014-02-22 02:00 PM,
Response2 : Start Time=2014-02-23 04:00 PM, EndTime = 2014-02-23 03:00 PM,
Response3 : Start Time=2014-02-23 4:30 PM, EndTime = 2014-02-23 05:30 PM,
Response4 : Start Time=2014-02-24 02:00 AM, EndTime = 2014-02-24 05:00 PM,
Response5 : Start Time=2014-02-25 11:00 AM, EndTime = 2014-02-25 12:00 PM,
所以,如果可能的话,我应该想出一些东西来说明这里找到了匹配项,如果没有找到匹配项,那么只查找所有用户的公共(public)时间是否存在。
时间 X 到时间 Y
(X 和 Y 之间的差异应至少为提到的 TimeSpan):本场比赛中的参加者人数 = N
(type = int, 1 或 2 个或尽可能多的匹配项)
Time A to Time B : Number of Attendee in this match = N
...
等等
附言:
它是一个 MVC 5.1 应用程序,数据库是使用代码优先方法创建的。 所以在数据库中有一个名为 Appointment 的表,它存储 StartDateTime 和 EndDateTime
这是我的DataModels
public class Appointment
{
[Key]
public Guid Id { get; set; }
public virtual ICollection<Attendee> Attendees { get; set; }
public DateTime StartDateTime { get; set; }
public DateTime EndDateTime { get; set; }
public TimeSpan MinAppointmentDuration { get; set; }
}
在这些日期之间,与会者(与会者)将给出他们的回应。每个人(将响应的人),他们的信息存储在名为 Attendees 的数据库表中
public class Attendee
{
public Guid AttendeeId { get; set; }
public virtual ICollection<Response> Responses { get; set; }
}
对于每个用户,他们的响应存储在 Responses 表中,其模型如下所示
public class Response
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public Guid AttendeeId { get; set; }
public DateTime StartDateTime { get; set; }
public DateTime EndDateTime { get; set; }
}
这就是我所做的,但它不起作用。
public class CommonTime
{
public DateTime Start { get; set; }
public DateTime End { get; set; }
public TimeSpan MinAppointmenttime { get; set; }
public int NumAttendees
{
get { return Responses.Select(x => x.AttendeeId).Distinct().Count(); }
}
public List<DataModels.Response> Responses { get; set; }
public CommonTime(DataModels.Response response, TimeSpan time)
{
Responses = new List<DataModels.Response>();
Start = response.StartDateTime;
End = response.EndDateTime;
MinAppointmenttime = time;
}
public void MergeCommonTime(DataModels.Response response)
{
if(Start <= response.StartDateTime && response.EndDateTime<=End)
{
Start = response.StartDateTime;
End = response.EndDateTime;
if((End-Start)>=MinAppointmenttime)
{
Responses.Add(response);
}
}
}
public List<CommonTime> FindCommonMatches(Guid appointmentId)
{
var appointment = _db.Appointments.Find(appointmentId);
var attendees = appointment.Attendees.ToList();
var matches = new List<CommonTime>();
bool isFirstAttendee = true;
foreach (var attendee in attendees)
{
if (isFirstAttendee)
{
foreach (var response in attendee.Responses)
{
matches.Add(new CommonTime(response, appointment.MinAppointmentDuration));
}
isFirstAttendee = false;
}
else
{
foreach (var response in attendee.Responses)
{
matches.ForEach(x => x.MergeCommonTime(response));
}
}
}
return matches;
}
}
所以在这种情况下,如果 Attendee X
(带有一些 Guid Id)提供他/她的可用性作为
和与会者 Y
提供他/她的可用性
这是我得到的常见匹配
正如我所解释的那样,这不是我想要的。
那么,我应该怎么做才能得到我想要的。
编辑:
基于 Zache 的回答
public class Meeting
{
public DateTime Start { get; set; }
public DateTime End { get; set; }
public List<DataModels.Attendee> Attendees { get; set; }
}
public class Requirement
{
public DateTime Start { get; set; }
public DateTime End { get; set; }
public TimeSpan MinHours { get; set; }
public int MinAttendees { get; set; }
public IEnumerable<Meeting> Meetings()
{
var possibleMeetings = new List<Meeting>();
var availableHours = (End - Start).TotalHours;
for (var i = 0; i < availableHours - MinHours.Hours; i++)
yield return new Meeting
{
Start = Start.AddHours(i),
End = Start.AddHours(i+MinHours.Hours)
};
}
}
public class Scheduler
{
public IEnumerable<Meeting> Schedule(Requirement req, List<DataModels.Attendee> attendees)
{
var fullMatches = new List<Meeting>();
var partialMatches = new List<Meeting>();
foreach (var m in req.Meetings())
{
foreach (var a in attendees)
{
if (fullMatches.Any())
{
if (a.Responses.Any(r => r.StartDateTime <= m.Start && r.EndDateTime >= m.End))
{
if (m.Attendees == null)
{
m.Attendees = new List<DataModels.Attendee> { a };
}
else
{
m.Attendees.Add(a);
}
}
else
{
break; // If we found one full match we aren't interested in the partials anymore.
}
}
else
{
if (a.Responses.Any(r => r.StartDateTime <= m.Start && r.EndDateTime >= m.End))
{
if (m.Attendees == null)
{
m.Attendees = new List<DataModels.Attendee> { a };
}
else
{
m.Attendees.Add(a);
}
}
}
}
if (m.Attendees != null)
{
if (m.Attendees.Count == attendees.Count)
fullMatches.Add(m);
else if (m.Attendees.Count >= req.MinAttendees)
partialMatches.Add(m);
}
}
return fullMatches.Any() ? fullMatches : partialMatches;
}
}
}
在存储库
public IEnumerable<Meeting> FindCommonMatches(Guid appointmentId)
{
var appointment = _db.Appointments.Find(appointmentId);
var attendees = appointment.Attendees.Where(a => a.HasResponded == true).ToList();
var req = new Requirement
{
Start = appointment.StartDateTime,
End = appointment.EndDateTime,
MinHours = appointment.MinAppointmentDuration,
MinAttendees = 1
};
var schedule = new Scheduler();
var schedules = schedule.Schedule(req, attendees);
return schedules;
}
开始日期:2/24/2014 11:30:00 AM
//我在创建约会时设置的
结束日期:2/25/2014 11:30:00 AM
当第一个用户响应以下数据时:
匹配结果:
当第二个与会者回复以下数据时
匹配结果
这里常见的匹配应该是:
Match1: 2/24/2014 10:00:00 AM to 2/24/2014 11:00:00 AM
Match2: 2/25/2014 9:00:00 AM to 2/25/2014 11:00:00 AM
最佳答案
以下 GetMeetingWindows
函数将返回所有匹配窗口和可用与会者的列表。然后可以根据结果的需要应用全部或最少参加者规定,例如
GetMeetingWindows(attendees, TimeSpan.FromMinutes(60)).Where(x => x.AvailableAttendees.Count() == attendees.Count());
我假设提供的与会者响应已经考虑到 session 可用的总体时间范围,但如果不是这种情况,则可以将此限制添加为额外的与会者,然后在结果中对其进行过滤,例如
GetMeetingWindows(...).Where(x => x.AvailableAttendees.Contains(meetingRoom));
代码:
public class Attendee
{
public ICollection<Response> Responses { get; set; }
}
public class Response
{
public DateTime StartDateTime { get; set; }
public DateTime EndDateTime { get; set; }
}
public class Window
{
public DateTime StartDateTime { get; set; }
public DateTime EndDateTime { get; set; }
public IEnumerable<Attendee> AvailableAttendees { get; set; }
}
public IEnumerable<Window> GetMeetingWindows(IEnumerable<Attendee> attendees, TimeSpan meetingDuration)
{
var windows = new List<Window>();
var responses = attendees.SelectMany(x => x.Responses).Where(x => x.EndDateTime - x.StartDateTime >= meetingDuration);
foreach(var time in (responses.Select(x => x.StartDateTime)).Distinct())
{
var matches = attendees.Select(x => new {
Attendee = x,
MatchingAvailabilities = x.Responses.Where(y => y.StartDateTime <= time && y.EndDateTime >= time.Add(meetingDuration))
});
windows.Add(new Window {
StartDateTime = time,
EndDateTime = matches.SelectMany(x => x.MatchingAvailabilities).Min(x => x.EndDateTime),
AvailableAttendees = matches.Where(y => y.MatchingAvailabilities.Any()).Select(x => x.Attendee)
});
}
foreach(var time in (responses.Select(x => x.EndDateTime)).Distinct())
{
var matches = attendees.Select(x => new {
Attendee = x,
MatchingAvailabilities = x.Responses.Where(y => y.EndDateTime >= time && y.StartDateTime <= time.Add(-meetingDuration))
});
windows.Add(new Window {
EndDateTime = time,
StartDateTime = matches.SelectMany(x => x.MatchingAvailabilities).Max(x => x.StartDateTime),
AvailableAttendees = matches.Where(y => y.MatchingAvailabilities.Any()).Select(x => x.Attendee)
});
}
return windows.GroupBy(x => new { x.StartDateTime, x.EndDateTime }).Select(x => x.First()).OrderBy(x => x.StartDateTime).ThenBy(x => x.EndDateTime);
}
public void Test()
{
var attendees = new List<Attendee>();
attendees.Add(new Attendee { Responses = new[] {
new Response { StartDateTime = DateTime.Parse("2014-02-24 9:00:00 AM"), EndDateTime = DateTime.Parse("2014-02-24 11:00:00 AM") },
new Response { StartDateTime = DateTime.Parse("2014-02-24 2:00:00 PM"), EndDateTime = DateTime.Parse("2014-02-24 4:00:00 PM") },
new Response { StartDateTime = DateTime.Parse("2014-02-25 9:00:00 AM"), EndDateTime = DateTime.Parse("2014-02-25 11:00:00 AM") },
new Response { StartDateTime = DateTime.Parse("2014-02-25 3:00:00 PM"), EndDateTime = DateTime.Parse("2014-02-25 5:00:00 PM") }
}});
attendees.Add(new Attendee { Responses = new[] {
new Response { StartDateTime = DateTime.Parse("2014-02-24 10:00:00 AM"), EndDateTime = DateTime.Parse("2014-02-24 11:00:00 AM") },
new Response { StartDateTime = DateTime.Parse("2014-02-24 4:00:00 PM"), EndDateTime = DateTime.Parse("2014-02-24 5:00:00 PM") },
new Response { StartDateTime = DateTime.Parse("2014-02-25 9:00:00 AM"), EndDateTime = DateTime.Parse("2014-02-25 11:00:00 AM") }
}});
var windows = GetMeetingWindows(attendees, TimeSpan.FromMinutes(60));
foreach(var window in windows)
{
Console.WriteLine(String.Format("Start: {0:yyyy-MM-dd HH:mm}, End: {1:yyyy-MM-dd HH:mm}, AttendeeCount: {2}", window.StartDateTime, window.EndDateTime, window.AvailableAttendees.Count()));
}
}
关于c# - 从每个用户提供的时间列表中找到所有共同时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21931540/