Acg N. .
Temat: Określenie wszystkich współdostępności zasobów. Może się...
Przy okazji realizacji pewnego projektu musiałem zmierzyć się z klasycznym problemem ustalenia czasów współdostępności zasobów.Dana jest lista zasobów (urządzeń, osób, pomieszczeń), które są potrzebne do wykonania pewnego zadania. Każdy zasób ma na dany dzień swój grafik dostępności Od - Do. Trzeba znaleźć moment, kiedy wszystkie zasoby są dostępne. Takich momentów w ciągu doby może być oczywiście wiele. Zakładany najmniejszy czas dostępności zasobu to pół godziny, ale ja zrobiłem to dla minuty.
Po narysowaniu wykresu, gdzie na osi OX jest czas, a na OY - zasoby, rozwiązanie nasunęło się samo.
Można je także, po niewielkiej przeróbce, wykorzystać do detekcji "kolizji" terminów.
Ciekaw jestem też Waszych pomysłów. Ten jest bardzo prosty, ale też i elastyczny.
PS: Kod to proof-of-concept, więc nie czepiamy się bzdurek, polskich komentarzy i nie hejtujemy, że "to przedszkole" :)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Test
{
class FromTo
{
public DateTime From { get; set; }
public DateTime To { get; set; }
}
class Program
{
static void Main(string[] args)
{
/* ---------------------------------- Definiujemy nasze "zasoby" ---------------------------------- */
List<List<FromTo>> ResAvailability = new List<List<FromTo>>();
List<FromTo> resAvail1 = new List<FromTo>();
resAvail1.AddRange(new FromTo[]
{
new FromTo() { From = new DateTime(2013, 7, 24, 8, 0, 0), To = new DateTime(2013, 7, 24, 11, 0, 0) },
new FromTo() { From = new DateTime(2013, 7, 24, 13, 0, 0), To = new DateTime(2013, 7, 24, 15, 0, 0) },
new FromTo() { From = new DateTime(2013, 7, 24, 16, 0, 0), To = new DateTime(2013, 7, 24, 21, 0, 0) }
});
List<FromTo> resAvail2 = new List<FromTo>();
resAvail2.AddRange(new FromTo[]
{
new FromTo() { From = new DateTime(2013, 7, 24, 9, 0, 0), To = new DateTime(2013, 7, 24, 10, 0, 0) },
new FromTo() { From = new DateTime(2013, 7, 24, 12, 0, 0), To = new DateTime(2013, 7, 24, 16, 30, 0) }
});
List<FromTo> resAvail3 = new List<FromTo>();
resAvail3.AddRange(new FromTo[]
{
new FromTo() { From = new DateTime(2013, 7, 24, 10, 0, 0), To = new DateTime(2013, 7, 24, 22, 0, 0) }
});
ResAvailability.Add(resAvail1);
ResAvailability.Add(resAvail2);
ResAvailability.Add(resAvail3);
/* ---------------------------------- Umieszczamy dostępności w tablicy minutowych slotów ---------------------------------- */
const int MINUTES_IN_DAY = 24 * 60;
int[] slots = new int[MINUTES_IN_DAY]; // utwórz listę slotów o rozmiarze = liczbie minut w dobie
foreach (var resAvail in ResAvailability)
{
foreach (FromTo range in resAvail)
{
for (int i = DateToMins(range.From); i <= DateToMins(range.To); i++) // daty początku i końca dostępności na minuty
{
slots[i]++; // Inkrementuj slot o indeksie odpowiadającym dacie skonwertowanej do minut.
// Jeśli zakresy dat się nie nakładają (nie mają prawa), to dla każdego zasobu
// indeks ten będzie odwiedzony tylko raz.
}
}
}
/* ---------------------------------- Pobieramy "współdostępności" ---------------------------------- */
List<FromTo> result = new List<FromTo>();
int resCount = ResAvailability.Count;
bool inside = false;
int begin = 0;
int end = 0;
for (int i = 0; i < slots.Length; i++)
{
if (slots[i].Equals(resCount)) // jeśli w slocie jest tyle jedynek ile zasobów, to mamy komplet
{
if (!inside)
{
begin = i; // współdostępność zaczyna się tu...
inside = true;
}
}
else
{
if (inside)
{
inside = false;
end = i - 1; // ... a kończy na ostatniej pozycji spełniającej w/w kryterium
if (!begin.Equals(end)) // wykluczamy przypadek 10:00 - 10:00
{
result.Add(new FromTo() { From = MinsToDate(begin), To = MinsToDate(end) });
}
}
}
}
/* ---------------------------------- Przetwarzamy wedle potrzeb... ---------------------------------- */
foreach (FromTo range in result)
{
Console.WriteLine("{0} - {1}", range.From.ToString("HH:mm"), range.To.ToString("HH:mm"));
}
Console.Read();
}
static int DateToMins(DateTime date)
{
return date.Hour * 60 + date.Minute;
}
static DateTime MinsToDate(int min)
{
int hours = min / 60;
int mins = min % 60;
return new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, hours, mins, 0);
}
}
}
Wynik:
13:00 - 15:00Ten post został edytowany przez Autora dnia 24.07.13 o godzinie 22:20
16:00 - 16:30