I have three rules:
A. Time slot between 9am and 3pm
B. Time slot betweem 3pm and 7pm
C. Time slot between 7pm and 9am
Currently I represented them as TimeSpans
public class Rule
{
public string Name {get; set;}
public TimeSpan From {get; set;}
}
List<Rule> rules = new List<Rule>()
{
new Rule() {From = new TimeSpan(9, 0, 0), Name = "A"},
new Rule() {From = new TimeSpan(15, 0, 0), Name = "B"},
new Rule() {From = new TimeSpan(19, 0, 0), Name = "C"}
};
My question is how to validate the time input let's say 9.10pm against that rules?
It should pick third rule.
With a slight modification by adding an end time to the Rule object
public class Rule {
public string Name { get; set; }
public TimeSpan From { get; set; }
public TimeSpan To { get; set; }
}
this extension method was used to check if a provided input is within the time range of the rule.
public static class RuleExtension {
public static bool Contains(this Rule rule, TimeSpan input) {
var value = TimeSpan.Parse(input.ToString());
var start = rule.From;
var end = rule.To;
if (end < start) {
//loopback
end += TimeSpan.FromHours(24);
if (value < start)
value += TimeSpan.FromHours(24);
}
return start.CompareTo(value) <= 0 && value.CompareTo(end) < 0;
}
}
The following unit test was used to validate the extension method and extraxt a rule from a collection. (Note: used FluentAssertions to assert results.)
[TestClass]
public class MyTestClass {
[TestMethod]
public void _ValidateTime() {
var rules = new List<Rule>()
{
new Rule() {From = new TimeSpan(9, 0, 0), To = new TimeSpan(15, 0, 0), Name = "A"},
new Rule() {From = new TimeSpan(15, 0, 0), To = new TimeSpan(19, 0, 0), Name = "B"},
new Rule() {From = new TimeSpan(19, 0, 0), To= new TimeSpan(5, 0, 0), Name = "C"}
};
var input = TimeSpan.Parse("21:10");
rules.FirstOrDefault(r => r.Contains(input))
.Should()
.NotBeNull()
.And
.Match((Rule r) => r.Name == "C");
input = TimeSpan.Parse("08:10");
rules.FirstOrDefault(r => r.Contains(input))
.Should()
.BeNull();
input = TimeSpan.Parse("18:10");
rules.FirstOrDefault(r => r.Contains(input))
.Should()
.NotBeNull()
.And
.Match((Rule r) => r.Name == "B");
input = TimeSpan.Parse("10:10");
rules.FirstOrDefault(r => r.Contains(input))
.Should()
.NotBeNull()
.And
.Match((Rule r) => r.Name == "A");
}
You can use the following:
DateTime input = DateTime.Now;
TimeSpan span = input.TimeOfDay;
for (int i = 0; i < rules.Count - 1; i++) {
if (span >= rules[i].From && span < rules[i + 1].From) {
return rules[i];
}
}
return rules[rules.Count - 1];
Something like below might do the trick:
var currentSpan = DateTime.Now - DateTime.Now.Date;
int ruleIndex = -1;
for (int i = 0; i < rules.Count - 1; i++)
{
if (currentSpan >= rules[i].From && currentSpan < rules[i + 1].From)
{
ruleIndex = i;
break;
}
}
if (ruleIndex == -1 && (currentSpan >= rules.Last().From || currentSpan < rules.First().From))
{
ruleIndex = rules.Count - 1;
}
var rule = rules[ruleIndex];
There are only 24 hours in a day. Could you just make a map array with an enum for assignments:
public enum Category
{
A,
B,
C
}
Then the array. So from your categories above 00:00 - 09:00 would be C.
Category[] values = new Category[24];
for(int i = 0;i<9;i++)
{
values[i] = Category.C;
}
So you could assign each hour similarly.
Now given an hour (say 6am) as an input you can use a switch:
switch(values[6]) // gets the appropriate category.
{
case Category.A:
// handle
break;
case Category.B:
// Handle
break;
case Category.C:
// handle
break;
default:
break;
}
Related
I'd like to reverse a list of objects with a TimeSpan property, which should maintain it's TimeSpan difference when reversing.
To give an example, consider a route from A to D with the following TimeSpans:
(A 12:00), (B 12:15), (C 12:40), (D 13:40).
Between A and B there is a 15 minute difference, between B and C there is a 25 minute difference and so on. I'd like to reverse this list in an efficient manner, where the result list would look like:
(D: 12:00), (C 13:00), (B 13:25), (A 13:40).
My first idea was creating a list of time differences and using that and the start time to create the new objects with the correct times, however I feel like the solution could be better.
Edit: Added my (working) sample solution. Any feedback is appreciated.
private IList<Activity> ReverseActivities(IList<Activity> activities)
{
IList<TimeSpan> timeDifferences = GetTimeDifferences(activities);
IList<Activity> resultList = new List<Activity>();
TimeSpan timeOfDay = activities.First().TimeOfDay;
for (int i = activities.Count - 1; i >= 0; i--)
{
resultList.Add(new Activity(activities[i].Name, timeOfDay));
timeOfDay = timeOfDay.Add(timeDifferences[i]);
}
return resultList;
}
private IList<TimeSpan> GetTimeDifferences(IList<Activity> activities)
{
IList<TimeSpan> timeDifferences = new List<TimeSpan>();
Activity prev = activities.First();
if (activities.Count > 1)
{
foreach (var curr in activities)
{
timeDifferences.Add(curr.TimeOfDay - prev.TimeOfDay);
prev = curr;
}
}
return timeDifferences;
}
Activity looks as follows:
public class Activity
{
public Activity(string name, TimeSpan timeOfDay)
{
this.Name = name;
this.TimeOfDay = timeOfDay;
}
public string Name { get; }
public TimeSpan TimeOfDay { get; }
}
One trick we can use is to have a single loop that finds the corresponding item from the end of the list based on the current index. We can do this like:
for (int i = 0; i < activities.Count; i++)
var correspondingIndex = activities.Count - i - 1;
Notice that:
When i is 0, correspondingIndex is the last index in the array.
When i is 1, correspondingIndex is the second-to-last index in the array.
When i is activities.Count - 1 (the last index), correspondingIndex is 0
Using this trick, we can get the corresponding time differences at the same time as we populate a new list of Activity objects.
Hopefully this code makes it a little clearer:
public static IList<Activity> ReverseActivities(IList<Activity> activities)
{
// If activities is null or contains less than 2 items, return it
if ((activities?.Count ?? 0) < 2) return activities;
// This will contain the reversed list
var reversed = new List<Activity>();
for (int i = 0; i < activities.Count; i++)
{
// Get the corresponding index from the end of the list
var correspondingIndex = activities.Count - i - 1;
// Get the timespan from the corresponding items from the end of the list
var timeSpan = i == 0
? TimeSpan.Zero
: activities[correspondingIndex + 1].TimeOfDay -
activities[correspondingIndex].TimeOfDay;
// The new TimeOfDay will be the previous item's TimeOfDay plus the TimeSpan above
var timeOfDay = i == 0
? activities[i].TimeOfDay
: reversed[i - 1].TimeOfDay + timeSpan;
reversed.Add(new Activity(activities[correspondingIndex].Name, timeOfDay));
}
return reversed;
}
In use, this would look like:
var original = new List<Activity>
{
new Activity("A", new TimeSpan(0, 12, 0)),
new Activity("B", new TimeSpan(0, 12, 15)),
new Activity("C", new TimeSpan(0, 12, 40)),
new Activity("D", new TimeSpan(0, 13, 40))
};
var reversed = ReverseActivities(original);
Here's the output in the debug window (compare original and reversed):
This is quite simple using a bit of TimeSpan maths.
IList<Activity> input = new List<Activity>()
{
new Activity("A", TimeSpan.Parse("12:00")),
new Activity("B", TimeSpan.Parse("12:15")),
new Activity("C", TimeSpan.Parse("12:40")),
new Activity("D", TimeSpan.Parse("13:40")),
};
TimeSpan min = input.Min(x => x.TimeOfDay);
TimeSpan max = input.Max(x => x.TimeOfDay);
IList<Activity> output =
input
.Select(x => new Activity(
x.Name,
x.TimeOfDay.Subtract(max).Duration().Add(min)))
.OrderBy(x => x.TimeOfDay)
.ToList();
That gives me:
I tested this and it works:
DateTime[] times = { new DateTime(2020, 06, 17, 12, 00, 00),
new DateTime(2020, 06, 17, 12, 15, 00), new DateTime(2020, 06, 17, 12, 40, 00),
new DateTime(2020, 06, 17, 13, 40, 00) };
List<DateTime> newTimes = new List<DateTime>();
newTimes.Add(times[0]);
for (int i = 1; i < times.Length; i++) {
DateTime d = newTimes[i - 1].Add(times[times.Length - i] - times[times.Length - i - 1]);
newTimes.Add(d);
}
Using LinkedList:
static void Main(string[] args)
{
var list = new List<Location>
{
new Location{Name = "A", TimeOffset = DateTimeOffset.MinValue.Add(new TimeSpan(12, 0, 0)) },
new Location{Name = "B", TimeOffset = DateTimeOffset.MinValue.Add(new TimeSpan(12, 15, 0)) },
new Location{Name = "C", TimeOffset = DateTimeOffset.MinValue.Add(new TimeSpan(12, 40, 0)) },
new Location{Name = "D", TimeOffset = DateTimeOffset.MinValue.Add(new TimeSpan(13, 40, 0)) },
};
var route = new LinkedList<Location>(list);
WriteToConsole("Before: ", route);
var reversedRoute = Reverse(route);
Console.WriteLine();
WriteToConsole("After: ", reversedRoute);
Console.WriteLine(); Console.ReadKey();
}
public static LinkedList<Location> Reverse(LinkedList<Location> route)
{
LinkedList<Location> retVal = new LinkedList<Location>();
DateTimeOffset timeOffset = DateTimeOffset.MinValue;
var currentNode = route.Last;
while (currentNode != null)
{
var next = currentNode.Next;
if (next == null)
{
// last node, use the first node offset
timeOffset = DateTimeOffset.MinValue.Add(route.First.Value.TimeOffset - timeOffset);
}
else
{
timeOffset = timeOffset.Add(next.Value.TimeOffset - currentNode.Value.TimeOffset);
}
retVal.AddLast(new Location { Name = currentNode.Value.Name, TimeOffset = timeOffset });
currentNode = currentNode.Previous;
}
return retVal;
}
public static void WriteToConsole(string title, LinkedList<Location> route)
{
Console.Write($"{title}: ");
foreach (var i in route)
{
Console.Write($"\t({i.Name}, {i.TimeOffset.Hour:D2}:{i.TimeOffset.Minute:D2})");
}
}
I'm querying a datatable and I seem stuck on selecting a group of groups.
This code
var grouping = table.AsEnumerable()
.Where(x => curveids.Contains(x.Field<short>("CurveID")) && x.Field<DateTime>("Timestamp").Hour >= hour && x.Field<DateTime>("Timestamp").Hour < (hour + 1))
.GroupBy(x => x.Field<DateTime>("Timestamp")).Where(x => x.Select(y => y["CurveID"]).Count() == curveids.Count);
Groups by timestamp and returns a group of x curves, where x = curveid.Count(). It contains 5000ish groups.
However for each day there can be more than one timestamp.
int nrdays = grouping.GroupBy(z => z.Key.Date).Count();
tells me there are 255 distinct days.
I would now like to group this again, but not by time stamp but by calendar day and then take the first (as in earliest) group for each day. I tried this:
var grouping2 = grouping.GroupBy(z => z.Key.Date).OrderBy(a => a.Key).Take(curveids.Count);
but this only returns 4 groups and I dont get why?
It should return 255 groups with each of them containing the same timestamp and x curveids, so x*255 record sets.
The datatable has 3 columns, Timestamp (DateTime), CurveID(short), Price(double).
UPDATE
As requested by Mr Skeet a full example:
public class listprx
{
public DateTime timestamp;
public int curveID;
public double prx;
}
static void Main(string[] args)
{
var data = new List<listprx>();
// populating data
for (int i = 0; i < 50000; i++)
{
Random rand = new Random(i);
var tempdt = new DateTime(2016, rand.Next(1, 12), rand.Next(1, 29), rand.Next(1, 23), rand.Next(1, 59), 0);
if(i % 3 == 0)
{
data.Add(new listprx { timestamp = tempdt, curveID = 1, prx = rand.Next(1,50)});
data.Add(new listprx { timestamp = tempdt, curveID = 2, prx = rand.Next(1, 50) });
}
else if (i % 5 == 0)
{
data.Add(new listprx { timestamp = tempdt, curveID = 1, prx = rand.Next(1, 50) });
}
else
{
data.Add(new listprx { timestamp = tempdt, curveID = 1, prx = rand.Next(1, 50) });
data.Add(new listprx { timestamp = tempdt, curveID = 2, prx = rand.Next(1, 50) });
data.Add(new listprx { timestamp = tempdt, curveID = 3, prx = rand.Next(1, 50) });
}
}
// setting hour criteria
int hour = 16;
int nrcurves = 3;
// grouping by timestamp and only take those where all curves are there, (as close to the desired time as possible
var grouping = data.Where(x => x.timestamp.Hour >= hour && x.timestamp.Hour < (hour + 1))
.GroupBy(x => x.timestamp).Where(x => x.Select(y => y.curveID).Count() == nrcurves);
// Grouping by day and take only the time stamp that is closest to the hour
// this fails
var grouping2 = grouping.GroupBy(z => z.Key.Date).OrderBy(a => a.Key).Take(nrcurves);
Console.WriteLine("Nr of timestamps with all curves {0}, nr of days {1}, nr of groups in second group {2}, expected same as nr days"
, grouping.Count(), grouping.GroupBy(z => z.Key.Date).Count(), grouping2.Count());
Console.ReadLine();
}
UPDATE 2
I have removed the random element and simplified further:
public class listprx
{
public DateTime timestamp;
public int curveID;
}
static void Main(string[] args)
{
var data = new List<listprx>();
// populating data
var tempdt = new DateTime(2016, 4, 6, 16, 1, 0);
for (int i = 0; i < 4; i++)
{
if (i == 2)
{
tempdt = tempdt.AddDays(1);
}
if(i % 2 == 0 )
{
data.Add(new listprx { timestamp = tempdt, curveID = 1});
}
else
{
data.Add(new listprx { timestamp = tempdt, curveID = 1});
data.Add(new listprx { timestamp = tempdt, curveID = 2});
}
tempdt = tempdt.AddMinutes(i+1);
}
// setting hour criteria
int hour = 16;
int nrcurves = 2;
//grouping by timestamp and only take those where all curves are there, (as close to the desired time as possible
var grouping = data.Where(x => x.timestamp.Hour >= hour && x.timestamp.Hour < (hour + 1))
.GroupBy(x => x.timestamp).Where(x => x.Select(y => y.curveID).Count() == nrcurves);
//Grouping by day and take only the time stamp that is closest to the hour
//this fails
var grouping2 = grouping.GroupBy(z => z.Key.Date).OrderBy(a => a.Key).Take(nrcurves);
Console.WriteLine("Nr of timestamps with all curves {0}, nr of days {1}, nr of groups in second group {2}, expected same as nr days"
, grouping.Count(), grouping.GroupBy(z => z.Key.Date).Count(), grouping2.Count());
Console.ReadLine();
}
The expected end result is:
Timestamp CurveID
------------------------
6/4/16 16:02 1
6/4/16 16:02 2
7/4/16 16:06 1
7/4/16 16:06 2
Edited answer working on your example.
Ok, I went trought your example and fixed some bugs and my answer. Let's clear code a bit and comment what went wrong where.
Our models will be
public class Curve
{
public int CurveID { get; set; }
public DateTime Timestamp { get; set; }
}
public class CurveGroup
{
public DateTime Timestamp { get; set; }
public IEnumerable<Curve> Curves { get; set; }
}
next is function to generate test data:
public static List<Curve> GetData()
{
var data = new List<Curve>();
var startTime = new DateTime(2016, 4, 6, 16, 1, 0);
for (int i = 0; i < 4; i++)
{
if (i == 2)
{
//startTime.AddDays(1); - this line does nothing, DateTime is an immutable struct so all function changing its value returns a new copy
startTime = startTime.AddDays(1);
}
if (i % 2 == 0)
{
data.Add(CreateNewCurve(startTime, 1));
}
else
{
data.Add(CreateNewCurve(startTime, 1));
data.Add(CreateNewCurve(startTime, 2));
}
//startTime.AddMinutes(i + 1); same issue as above
startTime = startTime.AddMinutes(i + 1);
}
return data;
}
public static Curve CreateNewCurve(DateTime time, int curveID)
{
return new Curve()
{
Timestamp = time,
CurveID = curveID
};
}
and here goes main function
static void Main(string[] args)
{
var data = GetData();
int hour = 16;
int totalCurveCount = 2;
var grouping = data
.Where(x => x.Timestamp.Hour >= hour && x.Timestamp.Hour < (hour + 1))
.GroupBy(x => x.Timestamp)
.Where(x => x.Count() == totalCurveCount); //there is no need to select curveId like in your code: Where(x => x.Select(y => y.curveID).Count() == nrcurves);
var grouping2 = grouping
.GroupBy(x => x.Key.Date)
.Select(x =>
new CurveGroup
{
Timestamp = x.Key,
Curves = x.OrderBy(c => c.Key).Take(totalCurveCount).SelectMany(c => c)
}
);
foreach (var g in grouping2)
{
foreach (var c in g.Curves)
{
Console.WriteLine(c.Timestamp);
Console.WriteLine(c.CurveID);
}
}
}
this returns expected results.
Your code failed because your second grouping is not taking (Take(nrcurves)) values in groups but groups themselves. So instead of returning 255 groups with 2 values in each you return 2 groups with all values in them.
Hope this fixes your issue.
I have a generic list of names whose number depends on what the user selects. I want to arrange those names in a range of times of the day that the user input before.
For example: we have 3 names, the user input 08:00-17:00. From 08:00-17:00 we have 9 hours -> 9/3=3, so arrange the names in a 3 hours templates.
This is how it looks in code:
List<string> myList = new List<string>();
myList.Add(Name1);
myList.Add(Name2);
myList.Add(Name3);
Console.WriteLine("Enter hours range: ");
Console.ReadLine(); //in this case the user input is 08:00-17:00
if (myList.Count == 3)
{
Console.WriteLine("8-11 " + myList.ElementAt(0)); //Name1
Console.WriteLine("11-14 " + myList.ElementAt(1)); //Name2
Console.WriteLine("14-17 " + myList.ElementAt(2)); //Name3
}
The problem comes, when there are more than 3 names and the hours are halved (lets say 17:30).
Any ideas on how to do this kind of thing?
You could do something like
private static void CalculateTimeIntervals()
{
var startTime = new DateTime(2014, 8, 15, 8, 0, 0);
var endTime = new DateTime(2014, 8, 15, 17, 0, 0);
var lengthOfTime = endTime - startTime;
var numberOfPeople = 4;
var dividedLengthOfTime = lengthOfTime.Ticks / numberOfPeople;
var people = new List<Person>();
for (int i = 1; i <= numberOfPeople; i++)
{
people.Add(
new Person
{
Id = i,
StartTime = startTime.AddTicks((dividedLengthOfTime * i) - dividedLengthOfTime),
EndTime = startTime.AddTicks(dividedLengthOfTime * i)
});
}
}
where Person looks like
public class Person
{
public int Id { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
}
How to return the best matching/next available product versionId from a list of available product versions ?
Here is the logic based on the sample data in the table
Look for the best matching version available less than 10.10.20 and should return its versionID
eg1:GetVersion("10.10.20") should return 5 ( because in table there is no "10,10,20" major.minor.build combination available ,so it should look for the best matching version
here the next available version is 10.7.1 ie., versionID 5
eg2:GetVersion("7.0.0") should return 3 ( because in table there is no "7,0,0" major.minor.build combination available ,so it should look for next available matching version .here the
next available version is 6.2.1 ie., versionID 3
eg3:GetVersion("7.5.1") should return 4 ,here exact match is available soit should return versionid 4
[Serializable]
public class ProductVersions
{
[Key]
public int Version_Id { get; set; }
public int Major { get; set; }
public int Minor { get; set; }
public int Build { get; set; }
}
Here is some sample data in my ProductVersions Table
[version_id , Major,Minor,Build]
1 3 0 1
2 4 10 5
3 6 2 1
4 7 5 1
5 10 7 1
6 11 10 10
Here is my method that is expected to return best available product version
private int GetVersion(string versionNumber)
{
int version-id=0;
version-id= //retrieve best matching version
return version-id
}
You can use the build-in Version class, since it already implements the <= operator you are basically looking for, and also can handle the string parsing for you:
var data = new List<Version>()
{
new Version(3,0,1),
new Version(4,10,5),
new Version(6,2,1),
new Version(7,5,1),
new Version(10,7,1),
new Version(11,10,10)
};
var case1 = new Version("10.10.20");
// match1 is 5; the index of a List is 0-based, so we add 1
var match1 = data.FindLastIndex(d => d <= case1) + 1;
var case2 = new Version("7.0.0");
// match2 is 3
var match2 = data.FindLastIndex(d => d <= case2) + 1;
var case3 = new Version("7.5.1");
// match3 is 4
var match3 = data.FindLastIndex(d => d <= case3) + 1;
It should be trivial to convert your sequence of ProductVersions to a list of Version objects.
If you don't want to use the Version class for whatever reason, you can implement the <= (and all other missing operators) yourself:
public class ProductVersions
{
//TODO error checking
public int Version_Id { get; set; }
public int Major { get; set; }
public int Minor { get; set; }
public int Build { get; set; }
public ProductVersions(int major, int minor, int build)
{
Major=major;
Minor=minor;
Build=build;
}
public ProductVersions(string version)
{
var tmp = version.Split('.');
Major = Int32.Parse(tmp[0]);
Minor = Int32.Parse(tmp[1]);
Build = Int32.Parse(tmp[2]);
}
public static bool operator == (ProductVersions a, ProductVersions b)
{
return a.Major==b.Major && a.Minor==b.Minor && a.Build==b.Build;
}
public static bool operator != (ProductVersions a, ProductVersions b)
{
return !(a==b);
}
public static bool operator <= (ProductVersions a, ProductVersions b)
{
if (a == b)
return true;
return a < b;
}
public static bool operator >= (ProductVersions a, ProductVersions b)
{
if (a == b)
return true;
return a > b;
}
public static bool operator < (ProductVersions a, ProductVersions b)
{
if(a.Major==b.Major)
if(a.Minor==b.Minor)
return a.Build < b.Build;
else
return a.Minor < b.Minor;
else
return a.Major < b.Major;
}
public static bool operator > (ProductVersions a, ProductVersions b)
{
if(a.Major==b.Major)
if(a.Minor==b.Minor)
return a.Build > b.Build;
else
return a.Minor > b.Minor;
else
return a.Major > b.Major;
}
And a simple test:
var data = new List<ProductVersions>()
{
new ProductVersions(3,0,1) { Version_Id = 1},
new ProductVersions(4,10,5) { Version_Id = 2},
new ProductVersions(6,2,1) { Version_Id = 3},
new ProductVersions(7,5,1) { Version_Id = 4},
new ProductVersions(10,7,1) { Version_Id = 5},
new ProductVersions(11,10,10) { Version_Id = 6}
};
// ensure data is sorted by version
data.Sort((a,b) => a > b ? 1 : a < b ? -1 : 0);
var case1 = new ProductVersions("10.10.20");
// match1 is 5
var match1 = data.Last(d => d <= case1).Version_Id;
var case2 = new ProductVersions("7.0.0");
// match2 is 3
var match2 = data.Last(d => d <= case2).Version_Id;
var case3 = new ProductVersions("7.5.1");
// match3 is 4
var match3 = data.Last(d => d <= case3).Version_Id;
I like Dominic's answer using the version class (why invent when it exists?) But in case you are wondering here is how to do it without using the Version class and you assume the list is already sorted (so you don't need to sort it like he did).
(TL;DR)
// assume verArray is already ordered (this would need to be sorted otherwise.)
// this where checks for less than or equal to.
int result = verArray.Where(v => (v.Major < major) ||
(v.Major == major && v.Minor < minor) ||
(v.Major == major && v.Minor == minor && v.Build <= build))
.Last().Version_Id;
The full code and test:
public ProductVersions[]verArray = {
new ProductVersions() { Version_Id = 1, Major = 3, Minor = 0, Build = 1 },
new ProductVersions() { Version_Id = 2, Major = 4, Minor = 10, Build = 5 },
new ProductVersions() { Version_Id = 3, Major = 6, Minor = 2, Build = 1 },
new ProductVersions() { Version_Id = 4, Major = 7, Minor = 5, Build = 1 },
new ProductVersions() { Version_Id = 5, Major = 10, Minor = 7, Build = 1 },
new ProductVersions() { Version_Id = 6, Major = 11, Minor = 10, Build = 10 },
};
void Main()
{
string test = "10.10.20";
Console.WriteLine(test + " gives "+GetVersion(test));
test = "7.0.0";
Console.WriteLine(test + " gives "+GetVersion(test));
test = "7.5.1";
Console.WriteLine(test + " gives "+GetVersion(test));
}
private int GetVersion(string versionNumber)
{
string [] input = versionNumber.Split(".".ToCharArray());
int major = int.Parse(input[0]);
int minor = int.Parse(input[1]);
int build = int.Parse(input[2]);
// assume verArray is already ordered (this would need to be sorted otherwise.
int result = verArray.Where(v => (v.Major < major) ||
(v.Major == major && v.Minor < minor) ||
(v.Major == major && v.Minor == minor && v.Build <= build))
.Last().Version_Id;
return result;
}
public class ProductVersions
{
public int Version_Id { get; set; }
public int Major { get; set; }
public int Minor { get; set; }
public int Build { get; set; }
}
This returns the following:
10.10.20 gives 5
7.0.0 gives 3
7.5.1 gives 4
I just checked for the samples you gave. This code works for me.
private int getver(int m, int n, int b)
{
List<ProductVersions> pv = new List<ProductVersions>();
pv.Add(new ProductVersions { Version_Id = 3, Major = 6, Minor = 2, Build = 1 });
pv.Add(new ProductVersions { Version_Id = 4, Major = 7, Minor = 5, Build = 1 });
pv.Add(new ProductVersions { Version_Id = 5, Major = 10, Minor = 7, Build = 1 });
pv.Add(new ProductVersions { Version_Id = 6, Major = 11, Minor = 10, Build = 10 });
int mm = m;
if (m == 0)
mm = int.MaxValue;
int nn = n;
if (n == 0)
nn = int.MaxValue;
int bb = b;
if (b == 0)
bb = int.MaxValue;
var v = pv.FindAll(mj => mj.Major <= m).FindAll(mn => n == 0 ? mn.Major <= mm - 1 && mn.Minor <= nn : mn.Minor <= n).FindAll(bl => b == 0 ? bl.Minor <= nn - 1 && bl.Build <= bb : bl.Build <= b).Last().Version_Id;
return v;
}
I am trying to shrink the list based on the criteria from major, minor and build levels and getting the last entity of the list. Here I assume that the list is sorted based on these values.
I found this one a quick and simple way, but with some limitations.
var v = from p in pv
select new { version = p.Version_Id, val = p.Major * 100000000 + p.Minor * 10000 + p.Build };
int vver=v.ToList().FindAll(pp => pp.val <= m * 100000000 + n * 10000 + b).Last().version;
ASP.NET using C#
The following are the Quarters for the financial year 2011-12
April 2011 to June2011 - Q1
July2011 to Sep2011 - Q2
Oct2011 to Dec2011 - Q3
Jan2012 to March 2012 - Q4
EDIT:
If i give a date as input then i need the output interms of the Quarter of that month:
Lets consider a date as input is 02-Jan-2012.
then i need the output as Q4
Lets take another date as input: 31May2012.
For this i need the output as Q1
Please help!!
Here is the function
public string GetQuarter(DateTime date)
{
// we just need to check the month irrespective of the other parts(year, day)
// so we will have all the dates with year part common
DateTime dummyDate = new DateTime(1900, date.Month, date.Day);
if (dummyDate < new DateTime(1900, 7, 1) && dummyDate >= new DateTime(1900, 4, 1))
{
return "Q1";
}
else if (dummyDate < new DateTime(1900, 10, 1) && dummyDate >= new DateTime(1900, 7, 1))
{
return "Q2";
}
else if (dummyDate < new DateTime(1900, 1, 1) && dummyDate >= new DateTime(1900, 10, 1))
{
return "Q3";
}
else
{
return "Q4";
}
}
Hope this could help.
static void Main(string[] args)
{
List<DateRange> range = new List<DateRange>();
//temp filling the data
DateTime start = new DateTime(2011, 4, 1);
range.Add(new DateRange() {From=start,To = start.AddMonths(3).AddMilliseconds(-1),Name="Q1"});
start = range.LastOrDefault().To.AddMilliseconds(1);
range.Add(new DateRange() { From = start, To = start.AddMonths(3).AddMilliseconds(-1), Name = "Q2" });
start = range.LastOrDefault().To.AddMilliseconds(1);
range.Add(new DateRange() { From = start, To = start.AddMonths(3).AddMilliseconds(-1), Name = "Q3" });
start = range.LastOrDefault().To.AddMilliseconds(1);
range.Add(new DateRange() { From = start, To = start.AddMonths(3).AddMilliseconds(-1), Name = "Q4" });
var order = range.OrderByDescending(r => r.IsCurrentQuater(DateTime.Now));
foreach (var itm in order)
Console.WriteLine(itm);
}
}
public class DateRange
{
public string Name { get; set; }
public DateTime From { get; set; }
public DateTime To { get; set; }
public bool IsCurrentQuater(DateTime date)
{
return date >= From && date <= To;
}
public override string ToString()
{
return string.Format("{0} - {1} to {2}", Name, From, To);
}
}
Regards.