Shorten a DateTime condition check - c#

if ((DateTime.Now.DayOfWeek != DayOfWeek.Friday && DateTime.Now.DayOfWeek != DayOfWeek.Saturday) &&
((DateTime.Now.Hour >= 10 && DateTime.Now.Hour < 13) || (DateTime.Now.Hour >= 20 && DateTime.Now.Hour < 23)))
I have to shorten this condition, any suggestions?

You could change the hours to use
(DateTime.Now.Hour % 12) +1 >= 10 && (DateTime.Now.Hour % 12) +1 < 13
Maybe even without the second check.
I don't think you can improve much more than that than looking for other methods like other answers
Update
I tested the above and its wrong, but this is more sadistic and works
var check = (DateTime.Now.Hours - 10 % 12) % 10;
var checkV = (DateTime.Now.Hours >= 10 && check < 3);
Test Code
for (int i = 0; i < 24; i++)
{
var check = (i - 10 % 12) % 10;
bool checkV = (i >= 10 && check < 3);
Console.WriteLine(i.ToString() + ": " + checkV.ToString());
}
Console.ReadKey();
Update 2
Complete shortened code
if( (int)DateTime.Now.DayOfWeek < 5 &&
DateTime.Now.Hours >= 10 &&
((DateTime.Now.Hours - 10 % 12) % 10) < 3)

Well, you could build an extension method:
public static bool BoundsCheck(this DateTime d, int min, int max, int min2, int max2)
{
return (d.DayOfWeek != DayOfWeek.Friday &&
d.DayOfWeek != DayOfWeek.Saturday &&
d.Hour >= min &&
d.Hour < max) ||
(d.Hour >= min2 && d.Hour < max2);
}
and then call it like this:
if (DateTime.Now.BoundsCheck(10, 13, 20, 23))...

Is this shorter? Maybe, but more important in my opinion it's more readable and maintainable:
var now = DateTime.Now;
var notAllowedDays = new[] { DayOfWeek.Friday, DayOfWeek.Saturday };
var allowedHours = Enumerable.Range(10, 3).Concat(Enumerable.Range(20, 3));
if(!notAllowedDays.Contains(now.DayOfWeek) && allowedHours.Contains(now.Hour))
{
}

if (!this.ItsPartyDay() && (this.ItsLunchTime() || this.ItsDinnerTime()))
{
...
}
private bool ItsPartyDay()
{
return (Int32)DateTime.Now.DayOfWeek >= 5;
}
private bool ItsLunchTime()
{
return (DateTime.Now.Hour >= 10 && DateTime.Now.Hour < 13);
}
private bool ItsDinnerTime()
{
return (DateTime.Now.Hour >= 20 && DateTime.Now.Hour < 23);
}

I don't think there is any reasonable solution but here a couple that come to mind. Use aliases for DateTime and DayOfWeek. One other option would be to assign all of those values to variables before the conditional.
So you could do things like;
string fri = DayOfWeek.Friday;
string sat = DayOfWeek.Saturday;
then use those in the conditional. Or;
using dt = DateTime;
Then you could do dt.Now.DayOfWeek
I personally would not recommend doing either of these things. You're not actually shortening the conditional, you're just refactoring. If you have a lot of these in one class it might be worth the trade off, otherwise it's probably not.
EDIT: The extension method suggestion by Michael Perrenoud is a reasonable solution that actually works really well.

Related

C# trying to solve a Project Euler problem 5

I'm new at C# and trying to solve:
What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?
This is what I wrote
int i = 1;
while (i % 2 != 0 || i % 3 != 0 || i % 4 != 0 || i % 5 != 0 || i % 6 != 0 || i % 7 != 0 || i % 8 != 0
|| i % 9 != 0 || i % 10 != 0 || i % 11 != 0 || i % 12 != 0 || i % 13 != 0 || i % 14 != 0
|| i % 15 != 0 || i % 16 != 0 || i % 17 != 0 || i % 18 != 0 || i % 19 != 0 || i % 20 != 0)
{
i++;
}
It works the answer is right, but can I optimize it
Thank you!
approach with Linq
while (Enumerable.Range(2,19).Any(x => i % x != 0))
{
i++;
}
The simplest next step is to take your long list of i % x != 0 tests and turn it into a loop:
bool IsEvenlyDivisible(int value, int range)
{
for (int i = 2; i <= range; i++)
{
if (value % i != 0)
{
return false;
}
}
return true;
}
int i = 1;
while (!IsEvenlyDivisible(i, 20))
{
i++;
}
You can even turn this while loop into a for loop:
for (int i = 1; IsEvenlyDivisible(i, 20); i++)
{
}
You can then make the IsEvenlyDivisible method simpler using linq, see fubo's answer.

Optimization Code

In my zeal to improve as developer, I want to know my code it is possible to improve, I am new in this and have very small logical
this is my code:
private int Period(DateTime date)
{
int period = 0;
if(date!= null)
{
int numeroMes = int.Parse(date.Month.ToString());
if(numeroMes <= 2)
{
period = 1;
}
else if (numeroMes <= 4 && numeroMes > 2)
{
periodo = 2;
}
else if (numeroMes <= 6 && numeroMes > 4)
{
period = 3;
}
else if (numeroMes <= 8 && numeroMes > 6)
{
period = 4;
}
else if (numeroMes <= 10 && numeroMes > 8)
{
period = 5;
}
else if (numeroMes <= 12 && numeroMes > 8)
{
period = 6;
}
}
return period ;
}
tkns for help me.
You can use the flooring of integer division to your favour which should be faster.
private int Period(DateTime date)
{
return (date.Month + 1) / 2;
}
However rounding might be easier to understand.
private int Period(DateTime date)
{
return (int)Math.Ceiling(date.Month / 2.0);
}
You can calculate the period since every period is just two months.
As DaveShaw pointed out, there is no need to check for the date being null because DateTime is a value type and thus cannot be null.
private int Period(DateTime date)
{
// already an int, no need to convert
var month = date.Month;
if (month % 2 == 0)
return month / 2;
else
return (month + 1) / 2
}
Here's another even shorter option that A.S. suggested.
private int Period(DateTime date)
{
return (int)Math.Ceiling(date.Month / 2.0);
// or...
// return (date.Month + 1) / 2;
// but I prefer the Ceiling option since it is more obvious what is happening
}
Alternatively, you could also reduce your code in this way...
private int Period(DateTime date)
{
int month = date.Month;
if (month <= 2)
return 1;
else if (month <= 4)
return 2;
else if (month <= 6)
return 3;
else if (month <= 8)
return 4;
else if (month <= 10)
return 5;
else
return 6;
}
Since I used return statements, there is no need for the second bool in each if statement.
As others said, this would better fit in https://codereview.stackexchange.com/, since it's not a question to a problem.
Now for some improvements to your code.
if(date!= null)
This will always be true, since DateTime is a value type (struct), which can't be null. Only Nullable<DateTime>/DateTime? can be null. So you can simply remove that.
int numeroMes = int.Parse(date.Month.ToString());
Here you are converting date.Month (which is an int) to a string and then parse it back to an int. Don't do that, date.Month is an int already:
int numeroMes = date.Month;
The rest is ok so far, but i guess in this line:
else if (numeroMes <= 12 && numeroMes > 8)
you really meant numeroMes > 10. Doesn't make a difference though as values 9 and 10 are matched before that.
Finally, you could shorten all those ifs to a simple formula:
return (int)Math.Ceiling(date.Month / 2.0);
Math.Ceiling rounds up the passed decimal number to the next integral number. So 1.5 would become 2 for example.

How to calculate the sum of a huge range filtered by a predicate in LINQ

I am trying to test the performance of three solutions for the Problem 1 from projecteuler.net by passing an int.MaxValue instead of 1000.
First solution:
long sum = SumDivisibleBy(3) + SumDivisibleBy(5) - SumDivisibleBy(15);
Console.WriteLine(sum);
Where SumDivisibleBy is:
public static long SumDivisibleBy(int k, int n = int.MaxValue)
{
long m = n / k;
return k * (m * (m + 1) / 2);
}
is faster (about 27 seconds) than
second solution:
long sum = 0;
for (int i = 0; i < int.MaxValue; i++)
{
if (i % 3 == 0 || i % 5 == 0)
{
sum += (long)i;
}
}
Console.WriteLine(sum);
The third solution (which is an elegant one in my opinion) is:
Console.WriteLine(Enumerable.Range(1, 999)
.Where(x => x % 3 == 0 || x % 5 == 0)
.Sum());
but I cannot achieve this (for testing performance purpose):
Console.WriteLine(Enumerable.Range(1, int.MaxValue)
.Where(x => x % 3 == 0 || x % 5 == 0)
.Sum());
because it gives me an OverflowException which is natural because of the nature of int Sum(this IEnumerable<int> source).
My question is this:
How can I upcast the int Sum(this IEnumerable<int> source) to the long Sum(this IEnumerable<long> source) in the code below:
Console.WriteLine(Enumerable.Range(1, int.MaxValue)
.Where(x => x % 3 == 0 || x % 5 == 0)
.Sum());
Try projecting the filtered sequence of ints to a sequence of longs:
.Where(x => x % 3 == 0 || x % 5 == 0)
.Select(x => (long)x)
.Sum()
Note that .Cast<long>() looks more elegant but won't work for this kind of conversion.
You could extend the Enumerable class like below:
public static class MyExtensions
{
public static IEnumerable<long> Range(long start, long count)
{
for (long i = start; i < start + count; i++)
{
yield return i;
}
}
}
This way you could make use of Sum method without having any issue, like below:
MyExtensions.Range(1, int.MaxValue)
.Where(x => x % 3 == 0 || x % 5 == 0)
.Sum());
Just for information... I tested all recommended solutions (LinqPad) and checked the time of execution.
Method 1) conversion with Select - time: 1:23.360s (mid)
.Select(x => (long)x)
Method 2) Extension method - time: 02:06.768s (slow)
MyExtensions.Range(1, int.MaxValue)
.Where(x => x % 3 == 0 || x % 5 == 0)
.Sum());
Method 3) suggested by T.Glatzer in comment to Ani's solution - time: 00:54.567 (quick)
Enumerable.Range(1, int.MaxValue).Where(x=> x%3==0 || x%5==0).Sum(x=>(long)x);
Conclusion:
Each method is much, much slower than your SumDivisibleBy function, so what are the benefits of Linq solutions other than elegant code? None.
Note: i do not tested it in other areas such as memory usage, CPU usage, etc.

Calculating a leap year without the leap year function

I need to calculate if the current year at the runtime of the program is a leap year (divisible by 4, not divisible by 100 but divisible by 400) but without using the DateTime.LeapYear property. Can anyone suggest anything?
//DateTimePicker code
private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
{
DateTime now;
int[] months = {31,28,31,30,31,30,31,31,30,31,30,31};
now = DateTime.Now.Date;
if (now.Year / 4 == 0 && now.Year / 400 == 0)
{
months(1) = 29;
}
}
I think this covers the three criteria:
var year = now.Year;
if (year % 4 == 00 && !(year % 100 == 0 && year % 400 != 0))
{
....
}
Use the modulus operator % when checking divisibility. Also, when changing an array, use array indexers [], not parentheses:
if (now.Year % 4 == 0 && now.Year % 400 == 0)
{
months[1] = 29;
}

Does this type of function or technique have a name?

HI there, I'm slightly new to programming, more of a hobby. I am wondering if a the following logic or technique has a specific name, or term. My current project has 7 check boxes, one for each day of the week. I needed an easy to save which boxes were checked.
The following is the method to saved the checked boxes to a single number. Each checkbox gets a value that is double from the last check box. When I want to find out which boxes are checked, I work backwards, and see how many times I can divide the total value by the checkbox value.
private int SetSelectedDays()
{
int selectedDays = 0;
selectedDays += (dayMon.Checked) ? 1 : 0;
selectedDays += (dayTue.Checked) ? 2 : 0;
selectedDays += (dayWed.Checked) ? 4 : 0;
selectedDays += (dayThu.Checked) ? 8 : 0;
selectedDays += (dayFri.Checked) ? 16 : 0;
selectedDays += (daySat.Checked) ? 32 : 0;
selectedDays += (daySun.Checked) ? 64 : 0;
return selectedDays;
}
private void SelectedDays(int n)
{
if ((n / 64 >= 1) & !(n / 64 >= 2))
{
n -= 64;
daySun.Checked = true;
}
if ((n / 32 >= 1) & !(n / 32 >= 2))
{
n -= 32;
daySat.Checked = true;
}
if ((n / 16 >= 1) & !(n / 16 >= 2))
{
n -= 16;
dayFri.Checked = true;
}
if ((n / 8 >= 1) & !(n / 8 >= 2))
{
n -= 8;
dayThu.Checked = true;
}
if ((n / 4 >= 1) & !(n / 4 >= 2))
{
n -= 4;
dayWed.Checked = true;
}
if ((n / 2 >= 1) & !(n / 2 >= 2))
{
n -= 2;
dayTue.Checked = true;
}
if ((n / 1 >= 1) & !(n / 1 >= 2))
{
n -= 1;
dayMon.Checked = true;
}
if (n > 0)
{
//log event
}
}
The method works well for what I need it for, however, if you do see another way of doing this, or a better way to writing, I would be interested in your suggestions.
Someone else mentioned bit masking, but I thought I would show you a way to simplify your code.
daySun.Checked = (n & 64) == 64;
daySat.Checked = (n & 32) == 32;
dayFri.Checked = (n & 16) == 16;
dayThu.Checked = (n & 8) == 8;
dayWed.Checked = (n & 4) == 4;
dayTue.Checked = (n & 2) == 2;
dayMon.Checked = (n & 1) == 1;
This resembles bitmasking. When I can find the blog I read this week using this exact example I'll post it!
Ah got it! Here it is.
You can then do things like:
DaysOfWeek week = DaysOfWeek.Sunday | DaysOfWeek.Monday;
to select Sunday and Monday. Or in your example, when you check the value of each checkbox you can do:
DaysOfWeek week = DaysOfWeek.None; // DaysOfWeek.None = 0
if (Monday.Checked)
{
week |= DaysOfWeek.Monday;
}
and to check if a particular day is set:
DaysOfWeek week = DaysOfWeek.Monday | DaysOfWeek.Tuesday;
// this will be FALSE (so Wednesday will remain unchecked) because "week" contains Monday/Tuesday, but not Wednesday.
if ((week & DaysOfWeek.Wednesday) == DaysOfWeek.Wednesday)
{
Wednesday.Checked = true;
}
EDIT:
.NET's built-in DayOfWeek does not allow for bitmasking multiple values, so you'll need to roll your own DaysOfWeek enum.
You could create an enum with all days and mark it with the attribute [Flags] then give each day the same value as your (bla.checked) ? XX..
then you could use +=, and, or to get the same functionality..
so to check if a value contains lets say monday you would do
if (myEnum & Days.Monday == Days.Monday)
{
...
}
It is called bitmasking and you can do the same thing more easily using an Enum with the Flags attribute.
It's called a bitfield, and yes, it's the most space-efficient way to solve this. Using separate booleans will probably use more memory, but IMO the better readability is worth six bytes or so.
you can use an enum... its more readable and pretty
public enum daysOfWeek
{
Mon = 1, Tue = 2, Wed = 4, Thu = 8, Fri = 16, Sat = 32, Sun = 64
}
you can hide the complexity in a function:
and it's better to bit-shift instead of dividing
private bool get_bit(int val, int idx)
{
return ((val >> idx) & 1) != 0;
}

Categories

Resources