8

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.

Andy Shellam
  • 15,403
  • 1
  • 27
  • 41
  • Thank you all very much for your answers.. Your examples are a perfect starting point for me to continue researching. It's always fun learning new things. –  Mar 19 '10 at 15:36
  • True programmers spirit right there. Make sure you stop by again if you get stuck on something. – ChaosPandion Mar 19 '10 at 15:39
  • http://en.wikipedia.org/wiki/Bit_field – Brian Mar 22 '10 at 19:16

7 Answers7

6

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
  • 77,506
  • 18
  • 119
  • 157
  • 1
    +1. Since he's probably not familiar with the C# bitwise operators, `&` performs a bitwise `AND`, and `|` performs a bitwise `OR` (there are others as well, but not applicable to this question). – Adam Robinson Mar 19 '10 at 15:12
4

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
  • 15,403
  • 1
  • 27
  • 41
  • 1
    -1: `(DayOfWeek.Tuesday | DayOfWeek.Monday) == DayOfWeek.Wednesday` – Brian Mar 19 '10 at 15:18
  • @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 Mar 19 '10 at 15:27
  • 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 Mar 19 '10 at 15:50
  • I removed the -1, since you do mention the issue in your edit and renamed the enumeration. – Brian Mar 19 '10 at 16:35
3

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

Peter
  • 37,042
  • 39
  • 142
  • 198
  • There is already a DayOfWeek enum in .NET. Also don't forget your brackets in the if clause: `if ((myEnum & Days.Monday) == Days.Monday)` – Andy Shellam Mar 19 '10 at 15:12
  • +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 Mar 19 '10 at 15:12
  • @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< – Brian Mar 19 '10 at 15:14
  • @Brian: A new enumeration with those values is probably a better idea than doing the bitshifting in code. – Adam Robinson Mar 19 '10 at 15:21
  • @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 Mar 19 '10 at 17:15
1

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

Lee
  • 18,529
  • 6
  • 58
  • 60
1

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
  • 13,904
  • 5
  • 39
  • 57
0

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
  • 3,855
  • 13
  • 43
  • 74
0

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
  • 936
  • 7
  • 12