I need to assign channel for each schedule. There can be as many concurrent events as number of channels allocated for the customer. I.e if the customer is allocated 3 channels then he can have 3 concurrent events. If a channel was allocated to a event then the same channel cannot to allocated to another event that falls under same time but the same channel can be allocate to another event if the time differs.
Channel Table
ID Name
1 Name1
2 Name2
3 Name3
Event Table
ID EventName StartTime EndTime ChannelID
1 Event1 11:30AM 12PM 1
2 Event2 11:30AM 11:40AM 2
3 Event3 11:40AM 12PM 2
4 Event4 12PM 12:30PM 1 0r 2
5 Event5 11:30AM 12:30PM 3
The above is the expected output.
I tried nested foreachloop one for channel and other for evets, but was not able to achieve and the complexity is really high. How to achieve this logic?
Pseudo Code:
for each channel
{
foreach existing events
{
if(sametime && same channel)
{
go for next channel
}
break;
}
assign current channel to new event
}
This fail when I try to create 3rd event.
You can rather loop through events for assigning channels to event, check out below pseudo code:
foreach events
{
foreach channels
{
if currentChannel is assigned
{
foreach assignedEvents
{
if assignedTime = currentEventTime
go to next Channel (continue)
}
currentEvent.Channel = currentChannel
break;
}
else
{
currentEvent.Channel = currentChannel
break;
}
}
}
Looks somewhat similar to Vehicle Routing Problem to me. Channels are the same as vehicles and events are like nodes in a directed acyclic graph with edges leading from one event to another if and only if the first event finishes earlier than the second one starts.
You should be able to find publicly available algorithms for solving this problem.
You have to generate all possibilities, and choose the best.
It is NP-complete problem, so there's no way to do it both fast and correct - either you do it fast by some heuristic, but then you don't know if it really did the best job, or you do it slow, and i mean slow, but you are sure the result is optimal.
Depends on the size of your data.
EDIT:
Example to demonstrate, that just assigning events to the first free channel won't always work.
We have 3 channels:
Ch1, Ch2, Ch3
We have to place 6 events:
E1-2 - starts at 1:00 ends at 2:59
E1-3 - starts at 1:00 ends at 3:59
E1-3 - starts at 1:00 ends at 3:59
E4 - starts at 4:00 ends at 4:59
E4 - starts at 4:00 ends at 4:59
E3-4 - starts at 3:00 ends at 4:59
If you just assign to the first free place you'll end up with:
Ch1: E1-2, E4
Ch2: E1-3, E4
Ch3: E1-3
and no place for E3-4
If you assigned them in different order, you'll get
Ch1: E1-2, E3-4
Ch2: E1-3, E4
Ch3: E1-3, E4
And all the events would fit.
So you have to do backtracing somehow.
I fixed some problems in the code. I think it should work now
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ChannelAllocator
{
class Program
{
const int _numberOfChannels = 10;
static void Main(string[] args)
{
Dictionary<int, List<TimeSlot>> occupiedChannels = new Dictionary<int, List<TimeSlot>>();
for (int i = 1; i <= _numberOfChannels; i++)
{
occupiedChannels.Add(i, new List<TimeSlot>());
}
/** Example **/
TimeSpan start = DateTime.Now.AddHours(-1.0).TimeOfDay;
TimeSpan end = DateTime.Now.TimeOfDay;
AssignChannel(occupiedChannels, ref start, ref end);
}
private static bool AssignChannel(Dictionary<int, List<TimeSlot>> occupiedChannels, ref TimeSpan start, ref TimeSpan end)
{
List<int> channels = occupiedChannels.Keys.ToList();
if (start >= end )
return false;
foreach (var item in channels)
{
List<TimeSlot> slots = occupiedChannels[item];
if (slots.Count == 0)
{
occupiedChannels[item].Add(new TimeSlot(start, end));
return true;
}
else
{
bool available = false ;
foreach (var slot in slots)
{
TimeSpan channelStartTime = slot.StartTime;
TimeSpan channelEndTime = slot.EndTime;
if (start >= channelStartTime && end <= channelEndTime ||
start <= channelStartTime && end <= channelEndTime && end >= channelStartTime
|| end >= channelEndTime && start >= channelStartTime && start <= channelEndTime)
{
available = false;
break;
}
else {
available = true;
}
}
if (available)
{
occupiedChannels[item].Add(new TimeSlot(start, end));
return true;
}
}
}
return false;
}
private class TimeSlot
{
public TimeSpan StartTime;
public TimeSpan EndTime;
public TimeSlot(TimeSpan start, TimeSpan end)
{
StartTime = start;
EndTime = end;
}
}
}
}
Related
I have a file with comma separated values (CSV), that have this format:
26/09/2015,GROUP_1,0,0,0,0,0,0,0,0,0,0,12345.006,12345.006,27469.005,27469.005,27983.005,27983.005,28081.005,0,0,0,28105.005,28105.005,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
Every number represents the work hours over an interval of 15 minutes, over the range 8:00 am - 8:00 pm. The first start time is 08:00:00) and the last start time will be 19:45:00; there are 49 "columns" of data.
0,0,0,0,0,0,0,0,0,0,12345.006,12345.006,27469.005,27469.005,27983.005,27983.005,28081.005,0,0,0,28105.005,28105.005,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
The date will be the date when the "event" happened and it's the date on the data. But I need to get the values that are the same and specify a time range. For example, those first two non-zero values are the same:
12345.006,12345.006
These start at 10:30 and 10:45; I need to merge these and report 12345 hours for the time span 10:30 - 11:00 am.
I read the file; I have those values as an array, and the problem I'm having is how to "group" the same values into the appropriate time ranges.
DateTime startDate = new DateTime(2015,08,05);
DateTime finisDahte = new DateTime(2015,08,05);
int column = 0;
for (int i = 0; i < data.Length; i++)
{
//timerange start with every 15 minutes by column
if (column >= 2)
{
if (data[i] != "0")
{
//Getting rid of decimals, they are not neccesary and that's how the file have it, I dont know why
if (data[i].Contains('.'))
{
data[i] = data[i].Substring(0, data[i].LastIndexOf('.'));
}
//we check if there is a next index to compare the same value
if ((i + 1) <= totalElementos)
{
var nextElem = data[i + 1];
if (nextElem != "0")
{
nextElem.Substring(0, nextElem.LastIndexOf('.'));
}
else
{
//the is no next element... something here
}
//CRUCIAL PART: if the current index it's the same as the next one, it means they share the time range
if (data[i] == nextElem)
{
//the same index as the next one
//I need to identify when it's the first time I'm comparing a value with the next one, so I can set a start date
//I need to sum the total amount of time ranges for every repetition they have and save when the value start and when the value is different (so it's a new value)
}
else
{
//it's not the same index, so technically the finishdate will be set here?
}
}
else
{
//there is not more indexes, so finishdate will be here
}
}
}
//column++;
}
Hope I could explain. Thanks
You need to generate a class like the code below. I changed the date to US format for testing. The code below reads from a string using StringReader and when reading from a file use StreamReader instead.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<DataSample> samples = new List<DataSample>();
string data = "9/26/2015,GROUP_1,0,0,0,0,0,0,0,0,0,0,12345.006,12345.006,27469.005,27469.005,27983.005,27983.005,28081.005," +
"0,0,0,28105.005,28105.005,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n";
StringReader reader = new StringReader(data);
string inputline = "";
while ((inputline = reader.ReadLine()) != null)
{
string[] dataArray = inputline.Split(new char[] { ',' });
DateTime startDate = DateTime.Parse(dataArray[0]);
startDate = startDate.AddHours(8);
DateTime timeCounter = startDate;
string groupName = dataArray[1];
for (int i = 2; i < dataArray.Length; i++)
{
if (dataArray[i] != "0")
{
DataSample newSample = new DataSample();
samples.Add(newSample);
newSample.name = groupName;
newSample.time = timeCounter;
newSample.value = double.Parse(dataArray[i]);
}
timeCounter = timeCounter.AddMinutes(15);
}
}
var groupByValue = samples.AsEnumerable()
.GroupBy(x => x.value)
.ToList();
foreach (var group in groupByValue)
{
Console.WriteLine("Value : {0}, Times : {1}", group.Key.ToString(), string.Join(",",group.Select(x => x.time.ToString())));
}
Console.ReadLine();
}
}
public class DataSample
{
public string name { get; set; }
public DateTime time { get; set; }
public double value { get; set; }
}
}
This is not a coding service; you need to go a little farther. You've done a good job of outlining your algorithm; now, you should put in a few print statements to track the operation of your code. Do the loops and if statements give you the control flow you expected? A good way to do this is to put your comments into print statements, such as in your last inside comment:
print "there is not more indexes, so finishdate will be here"
Also print the loop index, values you found, etc.
Once you have corrected any flow problems there, start filling in the comment-only blocks with useful code, a few lines or one block at a time.
When you hit a specific problem, post your code and the actual output. That's where StackOverflow is designed to help you.
In the meantime, I'd like to g a change to your outer loop. Let it be driven as a while loop, so you can freely advance your index as needed. Right now, you're keeping two variables for almost the same purpose: i and column. Instead, use just one, something like:
column = 0
while (column < data.Length)
// Find all of the indices with the same consecutive value
finish_index = column;
while data[start_column] = data[finish_index+1]
finish_index++;
// You now have the range of work slots to merge.
printf "Time slots %d - %d have %d work hours", column, finish_index, int(data[column])
column = finish_index+1
}
You will still have to convert column numbers to times: 15 minutes * column + 8:00am. I've also left out a few intermediate nice steps, but I think that you already have them in your comments.
Does this get you moving?
I have a little calendar tool in C# and I am trying to figure out how to do a conversion from one array of DateTime objects to another. Here are the details:
I start off with collection of DateTime object
IEnumerable<DateTime> slots = GetSlots();
where each DateTime represents that starting time of an available slot (think open slot in calendar) All slots are for 30 minutes This is a given. So for example:
var slots = new List<DateTime>()
slots.Add(DateTime.Today + new TimeSpan(5,00, 0));
slots.Add(DateTime.Today + new TimeSpan(9,00, 0));
slots.Add(DateTime.Today + new TimeSpan(9,30, 0));
slots.Add(DateTime.Today + new TimeSpan(10,00, 0));
slots.Add(DateTime.Today + new TimeSpan(10,30, 0));
slots.Add(DateTime.Today + new TimeSpan(11,00, 0));
slots.Add(DateTime.Today + new TimeSpan(16,30, 0));
in the above example, it means i am free:
From 5:00 - 5:30
From 9:00 - 9:30
From 9:30 - 10:00
From 10:00 - 10:30
From 10:30 - 11:00
From 11:00 - 11:30
From 4:30 - 5:00
because i take the time from the item in the collection as the start time and simply add 30 minutes to it and that is considered a free slot.
I now have the requirement to take a larger time window (lets use 2 hours) and find out how many 2 hour slots free i have so I now need to take this array of dates and "merge" into into bigger buckets. Given the bigger bucket is 2 hours (120 minutes), I want a function like this
IEnumerable<DateTime> aggregateArray = MergeIntoLargerSlots(slots, 120);
I would basically have to loop through the slots array above and "merge" items that are lined up next to each out to make bigger buckets. If any of the merged items is 2 hours long then that should show up as an entry in the resulting array. Using the example above the resulting aggregateArray would have 2 items in the collection it that would have the times:
9AM (because i have a free slot from 9-11 AM (120 mins).
9:30AM (because i have a free slot from 9:30-11:30 AM (120 mins).
NOTE: 30 minutes "chunks" are the smallest interval so DON'T need to include 9:05 to 11:05 as an example
So given the previous array I have two 2 hour windows of time free in the day
I am struggling to figure out how this MergeIntoLargerSlots function would work so i would hoping to get some suggestion for how to approach this problem.
This only works for half hour intervals, you can figure out to make it work for others if you need to.
public List<DateTime> MergeIntoLargerSlots(List<DateTime> slots, int minutes)
{
int count = minutes/30;
List<DateTime> retVal = new List<DateTime>();
foreach (DateTime slot in slots)
{
DateTime end = slot.AddMinutes(minutes);
if (slots.Where(x => x >= slot && x < end).Count() == count)
{
retVal.Add(slot);
}
}
return retVal;
}
Here's a brief explanation of my problem solving approach; I take in the minutes and the slots list. I add minutes to get an end time which gives me range. From there, I use the Where operator to produce and IEnumerable<DateTime> from slots that has the slots in that range. I compare the result to the count variable I got from doing minutes/slotLength if the numbers match then you have the necessary slots. With your sample data the result of the Where for 9 AM would have 4 values in it; 9, 9:30, 10 and 10:30, ofc the count is 4, 120/30 == 4, so that gets added to retVal. The same would be true for 9:30, no other times would be returned.
Evan beat me to and did it with one less loop, but here was my solution:
private List<DateTime> MergeArray(List<DateTime> slots, int minutes)
{
var segments = minutes / InitialSegment;
var validSegments = new List<DateTime>();
foreach (var slot in slots.OrderBy(x => x))
{
var validSegment = true;
for (var i = 0; i < segments-1; i++)
{
var next = slot.AddMinutes(InitialSegment * (i + 1));
if (slots.All(x => x != next))
{
validSegment = false;
break;
}
}
if (validSegment)
validSegments.Add(slot);
}
return validSegments;
}
Assuming that your original list is sorted (if it is not, make it so it is), you could loop through your original list and check whether adjacent items are consecutive (i.e. whether the start times have a distance of exactly 30 minutes). Always keep track of the first item in the current series of consecutive timeslots - once you reach four of them (with 4 consecutive 30 minutes timeslots adding up to a possible two-hour timeslot; other timeslot sizes obviously require different factors), save a new two-hour timeslot into your resulting list and update your reference to the beginning of the current series of consecutive items.
Untested, so please consider this as pseudocode:
var twoHourSlots = new List<DateTime>();
int consecutiveSlotsCount = 0;
DateTime? previousSlot;
foreach (DateTime smallSlotStart in slots) {
if (previousSlot.HasValue) {
if (smallSlotStart - previousSlot.Value == new TimeSpan(0, 30, 0)) {
consecutiveSlotsCount++;
} else {
consecutiveSlotsCount = 0;
}
}
if (consecutiveSlotsCount == 4) {
twoHourSlots.Add(smallSlotStart - new TimeSpan(1, 30, 0));
consecutiveSlots = 0;
previousSlot = null;
} else {
previousSlot = smallSlotStart;
}
}
Some things to note:
I am using arithmetic operators on DateTime values. Check the docs to find out more; they do handy things and often let you work with TimeSpan values automatically.
I am using a TimeSpan constructor that takes hours, minutes and seconds several times. So that's what the three numbers mean.
I have declared previousSlot, a variable that keeps track of the last slot looked at (to compare to the current one), as DateTime? (again, check the docs if you are not sure what a nullable type is). That is because in the first iteration of the foreach loop, there is no previous slot to look at and the loop has to behave differently.
Likewise, previousSlot is set to null when we have found a 2-hour slot, as the last 30-minute slot of the found 2-hour slot should not be counted to the next possible 2-hour slot.
Once four consecutive 30-minute slots have been found, one hour and thirty minutes are subtracted from the beginning of the last one. That is because the thirty minutes after the beginning of the last 30-minute slot will be part of the resulting 2-hour slot.
I would create a TimeInterval class since there are a lot of other interesting things you can do with it.
public sealed class TimeInterval
{
public DateTime Start { get; private set; }
public DateTime End { get { return Start.AddMinutes(Duration); } }
public double Duration { get; private set; }
public TimeInterval(DateTime start, int duration)
{
Start = start;
Duration = duration;
}
public IEnumerable<TimeInterval> Merge(TimeInterval that)
{
if(that.Start >= this.Start && that.Start <= this.End)
{
if(that.End > this.End)
Duration += (that.Duration - (this.End - that.Start).TotalMinutes);
yield return this;
}
else
{
yield return this;
yield return that;
}
}
}
And this is an O(n) merge algorithm that will work for intervals of arbitrary sizes (in minutes).
//the `spans` parameter must be presorted
public IEnumerable<TimeInterval> Merge(IEnumerable<TimeInterval> spans, int duration)
{
var stack = new Stack<TimeInterval>();
stack.Push(spans.First());
foreach (var span in spans.Skip(1))
foreach(var interval in stack.Pop().Merge(span)) //this enumeration is guaranteed to have either one element or two elements.
stack.Push(interval);
return from interval in stack where interval.Duration >= duration select interval;
}
I need to select N amount of events a day randomly, but they can't be too close to each other (M). So the N events have to be a at least M apart within a particular window (W). In this case the window I am thinking of is 12 hours.
N = the number of events
T = the time at which the event should occur (UTC)
M = the minimum factor they should be apart (Hours).
W = the window of the events (Now to Now + 12 hours).
U = the user (probably not important to this problem)
I could probably figure this out, but I thought it would be a fun StackOverflow question and interested how people would solve it.
Thanks in advance :)
Update: Moved answer to an answer
Try this:
It splits the available time (window - count * minimum) randomly, then sorts the times and adds the minimum amount to produce the final event array T[].
static Random rnd=new Random();
static void Main(string[] args)
{
double W=12;
double M=1.0;
int N=7;
double S=W-(N-1)*M;
double[] T=new double[N];
for(int i=0; i<N; i++)
{
T[i]=rnd.NextDouble()*S;
}
Array.Sort(T);
for(int i=0; i<N; i++)
{
T[i]+=M*i;
}
Console.WriteLine("{0,8} {1,8}", "#", "Time");
for(int i=0; i<N; i++)
{
Console.WriteLine("{0,8} {1,8:F3}", i+1, T[i]);
}
// With N=3, Window 12h, Min. Span = 5h
// # Time
// 1 0.468
// 2 5.496
// 3 10.529
// With N=7, Window 12h, Min. Span = 1h
// # Time
// 1 0.724
// 2 2.771
// 3 4.020
// 4 5.790
// 5 7.331
// 6 9.214
// 7 10.673
}
As a check also, when minimum times completely covers the time window then the events are equally spaced. So for 3 events on a 12hr window with minimum time 6hrs this algorithm produces events at 0.0 ,6.0 and 12.0 as expected.
You can use the idea I had for my question here: Generating non-consecutive combinations, essentially requiring that you only solve the M=0 case.
If you want to skip the description, the algorithm is given at the end of the post, which has no unpredictable while loops etc, and is guaranteed to be O(N log N) time (would have been O(N), if not for a sorting step).
Long Description
To reduce the general M case to the M=0 case, we map each possible combination (with the "aleast M constraint") to a combination without the "at least M" apart constraint.
If your events were at T1, T2, .., TN such that T1 <= T2 -M, T2 <= T3 - M ... you map them to the events Q1, Q2, .. QN such that
Q1 = T1
Q2 = T2 - M
Q3 = T3 - 2M
...
QN = TN - (N-1)M.
These Q satisfy the property that Q1 <= Q2 <= ... <= QN, and the mapping is 1 to 1. (From T you can construct the Q, and from Q you can construct the T).
So all you need to do is generate the Q (which is essentially the M=0 case), and map them back to the T.
Note that the window for generating Q becomes [Now, Now+12 - (N-1)M]
To solve the M=0 problem, just generate N random numbers in your window and sort them.
Final Algorithm
Thus your whole algorithm will be
Step 1) Set Window = [Start, End - (N-1)M]
Step 2) Generate N random numbers in the Window.
Step 3) Sort the numbers generated in Step 2. Call them Q1, Q2, .. , QN
Step 4) Create Ti with the formula Ti = Qi + (i-1)M, for i = 1 to N.
Step 5) Output T1,T2,..,TN
If we assume that events occur instantaneously (and, as such, can occur at time = end of window, you could do something like this:
//Using these, as defined in the question
double M;
int N;
DateTime start; //Taken from W
DateTime end; //Taken from W
//Set these up.
Random rand = new Random();
List<DateTime> times;
//This assumes that M is
TimeSpan waitTime = new TimeSpan.FromHours(M);
int totalSeconds = ((TimeSpan)end-start).TotalSeconds;
while( times.Count < N )
{
int seconds = rand.Next(totalSeconds);
DateTime next = start.AddSeconds(seconds);
bool valid = true;
if( times.Count > 0 )
{
foreach( DateTime dt in times )
{
valid = (dt > next && ((TimeSpan)dt - next) > waitTime) ? true : false;
if( !valid )
{
break;
}
}
}
if( valid )
{
times.Add(next);
}
}
Now, in a 12 hour window with at least an hour after each event before the next, you'd best have a small N - my psuedocode above does not check to see if it's possible to fit N events into X time with M hours between each event.
timeItems = new List();
int range;
double randomDouble;
for i = 1 to N
{
range = W/M;
//assumes generate produces a random number between 0 and 1 (exclusive)
randomDouble = RandomGenerator.generate() * (range);
T = Math.floor(randomDouble)*M;
timeItems.add(T);
}
return timeItems
First consider the job of generating one event such that there are (n-1) more events to generate (need to be separated by at least M each) and total of w time left.
Time t can be in between 0 to w-(n-1)m. The average value of t should be w/(n-1). Now, use any of your favorite distribution (I recommend poisson) to generate a random number with mean w/(n-1). If the number is higher than w-n-1)m, then generate again. That will give your t.
Recursively call (offset=offset+t, w=w-t, n=n-1, m=m) to generate more numbers.
def generate(offset, w, n, m):
mean = w/(n-1);
t=ininity;
while (t> (w-(n-1)m)):
t= poisson( w/(n-1) )
return [t+offset] + generate(offset+t, w-t, n-1, m)
I have not coded for corner conditions and other cases which I leave it to you.
Here is my solution. You get some weird behavior if your time apart and numOfEvents are conflicting. Play around with it and see what happens.
using System;
using System.Collections.Generic;
namespace RandomScheduler
{
class Program
{
public static Random R = new Random();
static void Main()
{
var now = DateTime.Now;
var random = new Random((int)now.Ticks);
const int windowOfHours = 12;
const int minimumTimeApartInHours = 2;
const int numOfEvents = 5;
// let's start the window 8 AM
var start = new DateTime(now.Year, now.Month, now.Day, 8, 0, 0, 0);
// let's end 12 hours later
var end = start.AddHours(windowOfHours);
var prev = null as DateTime?;
const int hoursInEachSection = windowOfHours / numOfEvents;
var events = new List<DateTime>();
for (var i = 0; i < numOfEvents; i++)
{
// if there is a previous value
// let's at least start 2 hours later
if (prev.HasValue)
start = prev.Value.AddHours(minimumTimeApartInHours);
DateTime? #event;
do
{
// pick a random double, so we get minutes involved
var hoursToAdd = random.NextDouble()*hoursInEachSection;
// let's add the random hours to the start
// and we get our next event
#event = start.AddHours(hoursToAdd);
// let's make sure we don't go past the window
} while (#event > end);
prev = #event;
events.Add(#event.Value);
}
Console.WriteLine(string.Join("\n", events));
Console.ReadLine();
}
}
}
For some testing I'm doing I need a C# function that takes around 10 seconds to execute. It will be called from an ASPX page, but I need the function to eat up CPU time on the server, not rendering time. A slow query into the Northwinds database would work, or some very slow calculations. Any ideas?
Try to calculate nth prime number to simulate CPU intensive work -
public void Slow()
{
long nthPrime = FindPrimeNumber(1000); //set higher value for more time
}
public long FindPrimeNumber(int n)
{
int count=0;
long a = 2;
while(count<n)
{
long b = 2;
int prime = 1;// to check if found a prime
while(b * b <= a)
{
if(a % b == 0)
{
prime = 0;
break;
}
b++;
}
if(prime > 0)
{
count++;
}
a++;
}
return (--a);
}
How much time it will take will depend on the hardware configuration of the system.
So try with input as 1000 then either increase input value or decrease it.
This function will simulate CPU intensive work.
Arguably the simplest such function is this:
public void Slow()
{
var end = DateTime.Now + TimeSpan.FromSeconds(10);
while (DateTime.Now < end)
/* nothing here */ ;
}
You can use a 'while' loop to make the CPU busy.
void CpuIntensive()
{
var startDt = DateTime.Now;
while (true)
{
if ((DateTime.Now - startDt).TotalSeconds >= 10)
break;
}
}
This method will stay in the while loop for 10 seconds. Also, if you run this method in multiple threads, you can make all CPU cores busy.
For maxing out multiple cores I adjusted #Motti's answer a bit, and got the following:
Enumerable
.Range(1, Environment.ProcessorCount) // replace with lesser number if 100% usage is not what you are after.
.AsParallel()
.Select(i => {
var end = DateTime.Now + TimeSpan.FromSeconds(10);
while (DateTime.Now < end)
/*nothing here */ ;
return i;
})
.ToList(); // ToList makes the query execute.
This is CPU intensive on a single thread/CPU, and lasts 10 seconds.
var endTime = DateTime.Now.AddSeconds(10);
while(true) {
if (DateTime.Now >= endTime)
break;
}
As a side note, you should not normally do this.
Just use
Thread.Sleep(number of milliseconds here);
You will have to add using System.Threading;
The problem:
I am in process of implementing a scheduler for my advisor in school. The scheduler supposes to setup a 15 minutes interval time slot from 8:00 AM to 5:00 PM, Monday to Friday. In addition, the advisor will have to specify the start and end dates of the scheduler. The scheduler will also feature an option to specify if the 15 minutes time slot is not open. Meaning my advisor will be able to mark specific time slot as NOT AVAILABLE.
What I have so far:
I have created a simple class:
public class TimeSlot
{
public DateTime dateTime
{
get;
set;
}
public bool isAvailable
{
get;
set;
}
TimeSlot(DateTime dt, bool Avalible)
{
dateTime = dt;
isAvailable = Avalible;
}
}
The class basically represents an object for one time slot in the scheduler. I also have a list of time slots that keeps a list of the valid time slots:
List<TimeSlot> TSList = new List<TimeSlot>();
Note that a valid time slot means the following:
Date is within: Monday to Friday.
Time is within: 8:00 AM to 5:00 PM
Time slots are within: 15 minutes interval.
In addition, I have a method that fill in the TSList as the following:
private void button_Next_Click(object sender, RoutedEventArgs e)
{
/* Getting the values of fromDate and toDate from the GUI controls*/
DateTime fromDate = datePicker1.SelectedDate.Value;
DateTime toDate = datePicker2.SelectedDate.Value;
while (fromDate <= toDate)
{
/*This ensures that we only deal with days Monday to Friday*/
if (fromDate.DayOfWeek.ToString() != "Saturday" && fromDate.DayOfWeek.ToString() != "Sunday")
{
/*PROBLEM HERE!!*/
}
/*Updating fromDate: Incrementing fromDate by 1 day*/
fromDate = fromDate.AddDays(1);
}
}
Notes that I was only able to satisfy the first condition in my valid time slot conditions. Thus, I was only able to restrict the dates to be within Monday to Friday range.
The questions:
I am trying to achieve the missing two valid conditions for a time slot:
How to restrict the times to be only 8:00am to 5:00 pm?
How to make time slots separated by 15 minutes interval?
First, please use DayOfWeek.Saturday and DayOfWeek.Sunday for the comparision, converting to a string is not necessary...
Then just use a simple loop like
DateTime startSlot = fromDate.Date.AddHours(8); // Starts at 8:00AM
while (startSlot.Hour < 17) {
// Construct time slot class
startSlot = startSlot.AddMinutes(15);
}
This gives you startSlot values starting at 8:00am at every date ranging to 5pm (i.e. the last one is 4:45pm).
Why are you considering building this out of nothing?
Why are you not starting with one of the many calendar management programs that are available off the shelf? For example, Microsoft Outlook contains calendar and schedule management, and you can do all of what you describe, easily. It also integrates with other scheduling tools via .ICS files, it syncs with mobile devices, syncs with Google Calendar, and so on.
But there are lots of other options. Google Calendar is another obvious one.
I don't know why you would ever consider starting from scratch. Unless it's an academic exercise (and no, I don't mean that you work in academia), then you should use larger building blocks to start.
It's like building a structure, starting with sand and water, instead of pre-fabricated concrete block.
Just quick implementation. Let me know if you need some comments.
// Round interval
const int roundInterval = 15;
var remainder = fromDate.TimeOfDay.Minutes % roundInterval;
var curTime = remainder == 0 ? fromDate : fromDate.AddMinutes(roundInterval - remainder);
curTime = curTime.AddSeconds(-curTime.TimeOfDay.Seconds);
var delta = TimeSpan.FromMinutes(roundInterval);
while (curTime < toDate)
{
while (curTime.DayOfWeek == DayOfWeek.Saturday || curTime.DayOfWeek == DayOfWeek.Sunday)
{
curTime = curTime.Date.AddDays(1);
}
if (curTime.TimeOfDay.Hours < 8)
{
curTime = curTime.AddHours(8 - curTime.TimeOfDay.Hours);
curTime = curTime.AddMinutes(-curTime.TimeOfDay.Minutes);
continue;
}
if (curTime.TimeOfDay.Hours >= 17)
{
curTime = curTime.AddHours(24 - curTime.TimeOfDay.Hours);
curTime = curTime.AddMinutes(-curTime.TimeOfDay.Minutes);
continue;
}
TSList.Add(new TimeSlot(curTime, true));
curTime = curTime.Add(delta);
}
}
DateTime myScheduledTimeSlot = new DateTime(2010, 10, 26, 8, 45, 0);
// Use existing check to check day of week constraint...
// Check if the datetime falls on a correct minute boundary
switch (myScheduledTimeSlot.Minute)
{
case 0:
case 15:
case 30:
case 45:
// The time slot is valid
break;
default:
// The time slot is not valid
break;
}
It is pretty simple to check whether it falls in a 15 minute slot as you don't have weird boundaries keeping every hour identical. I'd recommend checking out Quart.NET if you want to save some time doing eventing/scheduling.