tags:

views:

190

answers:

7

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.

+4  A: 

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.

Andy Shellam
-1: `(DayOfWeek.Tuesday | DayOfWeek.Monday) == DayOfWeek.Wednesday`
Brian
@Brian - Sorry, that was supposed to show that it would be FALSE because week only contains Monday/Tuesday. I've clarified this in the code so would appreciate the removal of the -1. Thanks!
Andy Shellam
No, I gave -1 because it is true, even though you said it was false. This is because you are using the existing system.DaysOfWeek enumeration (as opposed to the DaysOfTheWeek enumeration mentioned in the article), which is not intended for use as a bitmask.
Brian
I removed the -1, since you do mention the issue in your edit and renamed the enumeration.
Brian
+1  A: 

It is called bitmasking and you can do the same thing more easily using an Enum with the Flags attribute.

Lee
+3  A: 

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) { ... }

Petoj
Andy Shellam
+1 for suggesting an enumeration for the flag values. As is, the code has magic numbers. The mapping from day to number is stored in two places. As a further note, consider using 1<<0, 1<<1, 1<<2, etc. rather than explicitly typing out the numbers. This makes it more blatant that you are using powers of 2.
Brian
@Andy: The day of the week enumeration in .Net increments by + instead of <<. If he wants to use that, he'll have to use 1<<Days.Monday ... not that this is a bad idea.
Brian
@Brian: A new enumeration with those values is probably a better idea than doing the bitshifting in code.
Adam Robinson
Agree Adam, thanks for pointing that out Brian.
Andy Shellam
@Adam: True. Using MS's enumeration makes assumptions about how Microsoft implemented the enumeration (e.g. ms could choose values for the enumeration which causes the bitshift to overflow or whatever). These assumptions are highly unlikely to ever stop being right, but it's poor practice to rely on them.
Brian
+5  A: 

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;
ChaosPandion
Adam Robinson
+1  A: 

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.

Kilian Foth
+1: Readability trumps 3 bytes. The code footprint will likely even be smaller for the app.
SnOrfus
A: 

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
    }
Luiscencio
There is one in .NET - System.DayOfWeek
Andy Shellam
@Andy: Yes, but it increments by 1.
Brian
Ah fair point, didn't know that! In which case it couldn't be used for bitmasking.
Andy Shellam
A: 

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;
}
sisis