2

I have a dictionary:

   Dictionary<ICD_Map2, string> maps = new Dictionary<ICD_Map2, string>();

    public class ICD_Map2
    {
        public string call_type {get; set; }
        public string destination{get; set;} 

    }

maps.Add(new ICD_Map2() {call_type = "Mobile SMS", destination = "Australia"},"Local Text");
maps.Add(new ICD_Map2() {call_type = "Mobile SMS", destination = "International"},"International Text");

So what I want is, when I pass two variables:

Case 1 variable1 = "Mobile SMS" && variable2 = "Australia" I want a function to return "Local Text"

Case 2 "International Text" depending on my input variables matching ICD_Map2 definition "Mobile SMS" and "International".`

How do I construct this mapping function to return the First of the set from a set ofresults (if there are more than one)? This is a very simplified example, I have over 100 mappings.

Community
  • 1
  • 1
Saidur Rahman
  • 420
  • 2
  • 6
  • 19
  • 2
    A dictionary, when used correctly, does not have more than 1 result - it is a unique-key to value mapping (the values do not need to be unique). – Marc Gravell Oct 29 '12 at 08:23

5 Answers5

3

Although there are quite a few ways you could achieve this, the quickest and simplest I'd presonally use is LINQ's FirstOrDefault like this:

string var1 = "Mobile SMS";
string var2 = "Australia";

var item = maps.FirstOrDefault(e => e.Key.call_type == var1 && e.Key.destination == var2);
string result = (item == null) ? "No value" : item.Value;

In this case, if there is no corresponding match, you'd end up with result being null.

Paul Aldred-Bann
  • 5,840
  • 4
  • 36
  • 55
3

To use a dictionary, the key needs to support equality operations. For example:

public class ICD_Map2 : IEquatable<ICD_Map2>
{
    public ICD_Map2(string callType, string destination) {
        CallType = callType;
        Destination = destination;
    }
    public override int GetHashCode() {
        int result = 17;
        result = -13 * result +
            (CallType == null ? 0 : CallType.GetHashCode());
        result = -13 * result +
            (Destination == null ? 0 : Destination.GetHashCode());
        return result;
    }
    public override bool Equals(object other) {
        return Equals(other as ICD_Map2);
    }
    public bool Equals(ICD_Map2 other) {
        if(other == null) return false;
        if(other == this) return true;
        return CallType == other.CallType && Destination == other.Destination;
    }
    public string CallType {get; private set; }
    public string Destination{get; private set;} 
}

Note making it read-only is intentional: mutable keys are going to cause huge problems - avoid that.

Now you can use this as a key, for example:

var key = new ICD_Map2("Mobile SMS", "Australia");
string result;
if(maps.TryGetValue(key, out result)) {
    Console.WriteLine("found: " + result);
}

The reverse lookup is problematic, and cannot be optimised unless you have a second dictionary. A simple operation (performance O(n)) would be:

string result = "International Text";
var key = (from pair in maps
           where pair.Value == result
           select pair.Key).FirstOrDefault();
if(key != null) {
    Console.WriteLine("found: " + key);
}

Putting it all together:

static void Main()
{
    Dictionary<ICD_Map2, string> maps = new Dictionary<ICD_Map2, string> {
        {new ICD_Map2 ("Mobile SMS", "Australia"),"Local Text"},
        {new ICD_Map2 ("Mobile SMS", "International"),"International Text"}
    };

    // try forwards lookup
    var key = new ICD_Map2("Mobile SMS", "Australia");
    string result;
    if (maps.TryGetValue(key, out result))
    {
        Console.WriteLine("found: " + result);
    }

    // try reverse lookup (less efficient)
    result = "International Text";
    key = (from pair in maps
               where pair.Value == result
               select pair.Key).FirstOrDefault();
    if (key != null)
    {
        Console.WriteLine("found: " + key);
    }
}
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
2

Build custom comparer:

public class CusComparer: IEqualityComparer<ICD_Map2>
{
    public bool Equals(ICD_Map2 x, ICD_Map2 y)
    {
        return x.call_type.Equals(y.call_type) 
              && x.destination.Equals(y.destination);
    }

    public int GetHashCode(ICD_Map2 obj)
    {
        return obj.call_type.GetHashCode() 
                 ^ obj.destination.GetHashCode();
    }
}

Remember that Dictionary has another overload constructor with accepting IEqualityComparer:

var maps = new Dictionary<ICD_Map2, string>(new CusComparer());

maps.Add(new ICD_Map2() {
              call_type = "Mobile SMS", 
              destination = "Australia"},
         "Local Text");

maps.Add(new ICD_Map2() {
            call_type = "Mobile SMS", 
            destination = "International"},
         "International Text");

So you can get:

 var local = maps[new ICD_Map2() {
                     call_type = "Mobile SMS", 
                     destination = "Australia"}];
cuongle
  • 74,024
  • 28
  • 151
  • 206
0

I think this should work, will double check in a sec:

maps.Where(a => (String.IsNullOrEmpty(var1) || String.Compare(a.Key.call_type, var1) == 0) 
             && (String.IsNullOrEmpty(var2) || String.Compare(a.Key.destination, var2) == 0))
    .FirstOrDefault().Value`
cuongle
  • 74,024
  • 28
  • 151
  • 206
Mike Trusov
  • 1,958
  • 1
  • 15
  • 23
  • it does make it pointless to use a dictionary, though... since this doesn't benefit from *any* of the dictionary code – Marc Gravell Oct 29 '12 at 08:23
  • @MarcGravell Out of curiosity, what else could he use to resemble a mapping between ICD_Map objects and strings? – Mohammad Banisaeid Oct 29 '12 at 08:26
  • @MohammadBanisaeid he could make the key equatable, he could use a custom comparer, he could use tuples (which have inbuilt equatable implementation), he could use anonymous types, etc – Marc Gravell Oct 29 '12 at 08:38
  • @Mike - also - why use `string.Compare` here? the obvious method to use would be `string.Equals`...? – Marc Gravell Oct 29 '12 at 08:38
  • @Mark - RE it being **pointless to sue a dictionary**: yes, performance-wise this is crap, but it takes a fraction of time to implement compared to alternatives :P RE **string.Compare**: it's quite possible he'd want to treat variable-case strings the equal, and there's also CultureInfo to consider (may or may not be applicable in this case), generally when comparing strings I find that using String.Compare and specifying all the possible options explicitly is the safest way to go. – Mike Trusov Oct 29 '12 at 08:43
  • @Marc I prefer Compare for reasons listed here: http://blogs.msdn.com/b/bclteam/archive/2007/05/31/string-compare-string-equals-josh-free.aspx ... which might be out of date... according to http://stackoverflow.com/questions/44288/differences-in-string-compare-methods-in-c-sharp you're absolutely right though, bad habits are bad I guess – Mike Trusov Oct 29 '12 at 08:58
0

You have to implement IEquitable interface on ICD_Map2 and override GetHashCode function (it's better to override Equals(object) too even though it's not necessary as Dictionary uses generic IEquitable interface to find the key)

Anton Sorokin
  • 401
  • 1
  • 7
  • 10