Thursday, April 14, 2011

How to test if a C# Hashtable contains a specific key/value pair?

I'm storing a bunch of supposedly-unique item IDs as a key and the file locations as the value in a hash table while traversing a table. While I am running through it, I need to make sure that they key/location pair is unique or throw an error message. I have the hashtable set up and am loading the values, but am not sure what to test:

Hashtable check_for_duplicates = new HashTable();
foreach (object item in items)
{
    if (check_for_duplicates.ContainsKey(item["ItemID"]) &&
        //what goes here?  Would be contains item["Path"] as the value for the key)
    {
        //throw error
    }
}
From stackoverflow
  • If you were using Dictionary instead, the TryGetValue method would help. I don't think there is a really better way for the pretty much deprecated Hashtable class.

    object value;
    if (dic.TryGetValue("key", out value) && value == thisValue)
      // found duplicate
    
    Brian : which namespace should I use to enable Dictionaries? They're not in any of the default namespaces.
    Mike Rosenblum : The Dictionary class (http://msdn.microsoft.com/en-us/library/xfhwa508.aspx) was introduced in .NET 2.0 and is located in the System.Collections.Generic namespace.
  • if (check_for_duplicates.ContainsKey(item["ItemID"]) &&
        check_for_duplicates[item["ItemID"]] == item["Path"])
    {
        //throw error
    }
    
  • Try this:

    Hashtable check_for_duplicates = new HashTable();
    foreach (object item in items)
    {
        if (check_for_duplicates.ContainsKey(item["ItemID"]) &&
            check_for_duplicates[item["ItemID"]].Equals(item["Path"]))
        {
            //throw error
        }
    }
    

    Also, if you're using .NET 2.0 or higher, consider using Generics, like this:

    List<Item> items; // Filled somewhere else
    
    // Filters out duplicates, but won't throw an error like you want.
    HashSet<Item> dupeCheck = new HashSet<Item>(items); 
    
    items = dupeCheck.ToList();
    

    Actually, I just checked, and it looks like HashSet is .NET 3.5 only. A Dictionary would be more appropriate for 2.0:

    Dictionary<int, string> dupeCheck = new Dictionary<int, string>();
    
    foreach(Item item in items) {
        if(dupeCheck.ContainsKey(item.ItemID) && 
           dupeCheck[item.ItemID].Equals(item.Path)) {
            // throw error
        }
        else {
            dupeCheck[item.ItemID] = item.Path;
        }    
    }
    
    Brian : Found a minor error: check_for_duplicates[item["ItemID"]] == item["Path"] should be check_for_duplicates[item["ItemID"]].Equals(Item["Path"])
    mquander : Regarding HashSet; you can compare the count in the resulting set with the count of the original collection if you want to figure out whether there were dupes. (Warning: not performant.)
  • It kinda depends what the items array is... you'll want something like:

    check_for_duplicates.ContainsValue(item["Path"]);
    

    Assuming that the item is some form of lookup. Really you need to be casting item, or using a type system to actually access any values via an index.

    Ian : My bad... I hadn't realised that there was an AND clause in the original question.
  • ContainsKey is the best method.

    If you aren't forced to use .NET 1.1 I would use the Dictionary introduced in .NET 2.0.

    It is much better than a Hashtable from performance and is strongly typed.

    Dictionary<string, int> betterThanAHash = new Dictionary<string, int>();
    
    betterThanAHash.ContainsKey("MyKey");
    
    Brian : Which namespace should I use for this? Dictionary isn't in the default namespaces I'm using.
    Svish : then add the namespace for Dictionary =)
    TheMissingLINQ : @Brian - System.Collections.Generic
  • Hashtable check_for_duplicates = new HashTable();
    
    foreach (object item in items) 
    {
        if (check_for_duplicates.ContainsKey(item["ItemID"]) && check_for_duplicates[item["ItemID"]] == item["Path"])
        {
            //throw error
        } 
    }
    

    I do believe this is what you're looking for.

    EDIT - Looks like I was beaten to the punch :P

    Brian : Almost, your example doesn't quite work (missing a ] on: check_for_duplicates[item["ItemID"]
    Matt Grande : That's correct, it's been fixed.
  • Why not use a Dictionary instead?

    That will throw an ArgumentException if you try to Add a key that already exists in the Dictionary.

    That way you can catch the duplicate at the moment it is being added, rather than performing a check_for_duplicates test later.

  • You didn't say what version of things you were using. Is there a reason you must use a Hashtable vs a HashSet? You would have no need to check for duplicates if your data structure didn't allow them. See also:

    http://www.vcskicks.com/csharp_data_structures2.html

    Other than that, the question of how to accomplish the same thing in Hashtable has already been answered here. I'm just pointing out that you don't need to do all the pathological checking if you forbid it in the first place.

0 comments:

Post a Comment