1

there is a method that receives an int parameter and returns a string by checking parameter through a set of if...else statements :

if(param == 1)
{
    return "1";
}
else if(param ==20)
{
    return "20";
}
else
{
    if(param <= 10)
    {
        return "below 10";
    }
    else if(param <= 30 )
    {
        return "below 30";
    }
    ...
}

I wonder if it is possible to put these ">= , <=" conditions in a dictionary

Habib
  • 219,104
  • 29
  • 407
  • 436
mohsen dorparasti
  • 8,107
  • 7
  • 41
  • 61
  • 1
    http://stackoverflow.com/questions/2147505/a-dictionary-object-that-uses-ranges-of-values-for-keys – Habib Oct 02 '12 at 06:47

5 Answers5

3

You can use Dictionary<Func<int, bool>, string>:

    private string Do(int input)
    {
        var dic = new Dictionary<Func<int, bool>, string>
            {
                {param => param == 1, "1"},
                {param => param == 20, "20"},
                {param => param <= 10, "below 10"},
                {param => param <= 30, "blow 30"}
            };

        return dic.First(pair => pair.Key(input)).Value;  
    }

Edit:

Comment from @Maarten is correct, Dictionary does not ensure the order of item, List of KeyValuePair should be the best this case:

    private string Do(int input)
    {
        var pairs = new List<KeyValuePair<Func<int, bool>, string>>
            {
                {param => param == 1, "1"},
                {param => param == 20, "20"},
                {param => param <= 10, "below 10"},
                {param => param <= 30, "blow 30"}
            };

        var pair = pairs.FirstOrDefault(pair => pair.Key(input));
        if (pair == null) return string.Empty; // return whatever you want

        return pair.Value;
    }
cuongle
  • 74,024
  • 28
  • 151
  • 206
  • yes , but as mentioned in http://stackoverflow.com/q/2147505/1140531 , this approach has performance issues , is it true ? – mohsen dorparasti Oct 02 '12 at 07:18
  • 2
    @mohsen.d This approach will execute every condition until the first match. You usually want a dictionary because you want to jump directly to the correct item, without going past any others. Clever trick, though. The overhead will not be too bad if you have a limited number of items. – Hans Kesting Oct 02 '12 at 07:31
  • @mohsen.d: no, it's good performance, use dic to make you find the value with O(1). The link you give is the different case – cuongle Oct 02 '12 at 07:36
  • It's not O(1) just because you're using a dictionary. You're iterating through the values, not accessing them by key. – Rawling Oct 02 '12 at 07:44
  • 2
    Also, the ordering of the items in a dictionary is not guaranteed. Therefore you cannot predict that the check param <= 10 is done before param <= 30. Thus, I think this solution is not usable. – Maarten Oct 02 '12 at 07:46
  • 2
    Sorry, yes, you're iterating through the keys, not the values. You're not at any point using the O(1) lookup of the dictionary, though - this would work just as well using a list of tuples, and such a list would guarantee ordering. (As you've just shown :) ) – Rawling Oct 02 '12 at 07:51
  • 1
    Nitpicking: if you run the method for value 99 you get an exception. – Maarten Oct 02 '12 at 08:04
  • @Maarten: :), added line to check null – cuongle Oct 02 '12 at 08:06
  • @CuongLe : thank you . your updated code has a problem . KeyValuePair can't contain a collection of s , just one .It should be a List , right ? – mohsen dorparasti Oct 02 '12 at 11:25
0

Can use, for example, a dictionary.

Just an example of pseudocode:

var dic = new Dictionary<int,string>{{1,"1"}, {20, "20"}...}

and instead of long if

string value = null; 
dic.TryGetValue(param, out value);
Tigran
  • 61,654
  • 8
  • 86
  • 123
0

Your operations are not well designed for dictionary. consider the following two case

param == 29 and param ==28

both will give output "below 30". If the range of param variable is large then you have to put all the probable values and there corresponding output strings manually in the dictionary. Is it seems a good idea???

Debobroto Das
  • 834
  • 6
  • 16
0

No, Dictionary is not designed for that. If you really got too many comparision conditions you could put the comparatees in an array or list, put the values in another array/list in corresponding order, then you use binarysearch to find the key's index, and use the index to get the value. Here is an example:

    static string find(int val)
    {
        int[] keys = {30,40,50};
        string[] messages = {"Below 30","Below 40","Below 50"};
        int idx = Array.BinarySearch(keys,val);
        if(idx < 0)idx = ~idx;
        return idx < 3 ? messages[idx] : "Off the chart!";
    }

    public static void Main (string[] args)
    {
        Console.WriteLine (find(28));
        Console.WriteLine (find(50));
        Console.WriteLine (find(100));
    }
Need4Steed
  • 2,170
  • 3
  • 22
  • 30
0

I tired the following. Please let us know if you run into any issues with this:

            int testInput = 15;

            Func<int, bool> delegateForCondition1 = param => param == 1;
            var conditionsSet = new HashSet<KeyValuePair<Func<int, bool>, String>> 
                        { 
                          new KeyValuePair<Func<int, bool>, String>(delegateForCondition1, "It is 1"), 
                          new KeyValuePair<Func<int, bool>, String>(param => param <= 10 , "below 10"),
                          new KeyValuePair<Func<int, bool>, String>(param => param <= 30 , "below 30")
                        };


            foreach (KeyValuePair<Func<int, bool>, String> pair in conditionsSet)
            {
                Func<int, bool> currentKeyAsDelegate = pair.Key;
                bool currentResult = pair.Key(testInput);
                Console.WriteLine(currentKeyAsDelegate + "---" + currentResult);
            }

            //Select the first matching condition
            KeyValuePair<Func<int, bool>, String> selectedPair = conditionsSet.FirstOrDefault(p => p.Key(testInput));
            if (selectedPair.Key != null)
            {
                Console.WriteLine(selectedPair.Value);
            }


            Console.ReadLine();
LCJ
  • 22,196
  • 67
  • 260
  • 418