Neil N
Neil N

Reputation: 25258

How to dynamically switch between comparing Less Than, Greater Than, or Equal To?

Basically I am giving the user an option to filter a set of files based on thier size.

The user picks a comparison type (Greater Than, Less Than, Equal To) from a drop down list, and then enters a size, in bytes, to compare to. This is what I have so far:

switch (cmboCompareType.SelectedText)
{
    case "Greater Than":
        fileOK = fi[i].Length > int.Parse(txtByteValue.Text);
        break;
    case "Less Than":
        fileOK = fi[i].Length < int.Parse(txtByteValue.Text);
        break;
    case "Equal To":
        fileOK = fi[i].Length == int.Parse(txtByteValue.Text);
        break;
}

Is there a more elegant way to do this sort of comparison without repeating so much code in C#?

Upvotes: 4

Views: 6190

Answers (8)

Jon Skeet
Jon Skeet

Reputation: 1500215

Two options:

  1. Use CompareTo and Sign:
int requiredSign;
switch (cmboCompareType.SelectedText)
{
   case "Greater Than": requiredSign = 1; break;
   case "Less Than": requiredSign = -1; break;
   case "Equal To": requiredSign = 0; break;
   default: throw new ArgumentException();
}
fileOK = Math.Sign(fi[i].Length.Compare(txtByteValue.Text)) == requiredSign;
  1. Use a delegate:
static readonly Func<int, int, bool> GreaterThan = (x, y) => x > y;
static readonly Func<int, int, bool> LessThan = (x, y) => x < y;
static readonly Func<int, int, bool> Equal = (x, y) => x == y;
...

Func<int, int, bool> comparison;
switch (cmboCompareType.SelectedText)
{
   case "Greater Than": comparison = GreaterThan; break;
   case "Less Than": comparison = LessThan; break;
   case "Equal To": comparison = Equal; break;
   default: throw new ArgumentException();
}
fileOK = comparison(fi[i].Length, int.Parse(txtByteValue.Text));

Upvotes: 20

David
David

Reputation: 19677

I'm not a fan of case statements, same thing though, just another way.


var fileOK = new Dictionary<string, Func<int, int, bool>>
    (StringComparer.OrdinalIgnoreCase)
    {
        { "Greater Than", (x, y) => x > y },
        { "Less Than", (x, y) => x < y },
        { "Equal To", (x, y) => x == y }
    }[cmboCompareType.SelectedText](fi.Length, int.Parse(txtByteValue.Text));

Upvotes: 5

Neil N
Neil N

Reputation: 25258

My own idea, inspired by the solutions that used Math.Sign(). Since the drop down box has three values, which will have an index of 0,1,and 2, I could subtract 1 to get -1,0,1, then use that to compare with the sign, as such:

int sign = Math.Sign(fi[i].Length.CompareTo(int.Parse(txtByteValue.Text)));
fileOK = sign == (cmboCompareType.SelectedIndex - 1);

This would be dependent on the items in the listbox being put in this specific order:
Less Than
Equal To
Greater Than

And of course would only work if these are the only values that will ever be in the listbox. Probably not the best solution, but I got a kick out of the fact that I accomplished this in only two lines of code.

EDIT: Techincally I could simplify this down to a single line of code:

fileOk=(cmboCompareType.SelectedIndex-1) == Math.Sign(fi[i].Length.CompareTo(int.Parse(txtByteValue.Text)));

Upvotes: 0

Jeff Hornby
Jeff Hornby

Reputation: 13640

You could also add the values -1, 0, 1 to the value property of each combo box item and then the code would look like:

fileOK = fi[i].Length.CompareTo(int.Parse(txtByteValue.Text) == cmboCompareType.SelectedValue;

Upvotes: 1

Jeff Hornby
Jeff Hornby

Reputation: 13640

Create an extension method on int

public static int Compare(this int a, int b, string compareType)
{
    switch (CompareType)
    {
        case "Greater Than":
            return fi[i].Length > int.Parse(txtByteValue.Text);
            break;
        case "Less Than":
            return fi[i].Length < int.Parse(txtByteValue.Text);
            break;
        case "Equal To":
            return fi[i].Length == int.Parse(txtByteValue.Text);
            break;
    }
}

and then use it as:

fileOK = fi[i].Length.Compare(int.Parse(txtByteValue.Text), cmboCompareType.SelectedTex);

Upvotes: 1

Reed Copsey
Reed Copsey

Reputation: 564383

If you have a map, you can use something like:

private int CompareOp(string Text)
{
    switch (cmboCompareType.SelectedText)
    {
        case "Greater Than": 
            return 1;
        case "Less Than": 
            return -1;
        case "Equal To": 
            return 0;
    }
}

// In your method:
fileOK = (fi[i].Length.CompareTo(value) == CompareOp(cmboCompareType.SelectedText);

Upvotes: 1

John Kugelman
John Kugelman

Reputation: 361585

int actual = Math.Sign(fi[i].Length.CompareTo(int.Parse(txtByteValue.Text)));
int expected;

switch (cmboCompareType.SelectedText)
{
    case "Greater Than": expected = +1; break;
    case "Less Than":    expected = -1; break;
    case "Equal To":     expected =  0; break;
}

fileOK = (actual == expected);

Upvotes: 1

jrista
jrista

Reputation: 32960

int value = int.Parse(txtByteValue.Text);
int len = fi[i].Length;

switch (cmboCompareType.SelectedText)
{
    case "Greater Than": fileOK = len > value; break;
    case "Less Than": fileOK = len < value; break;
    case "Equal To": fileOK = len == value; break;
}

TADA! Less repetition. ;P

Upvotes: 10

Related Questions