Search code examples
c#matchidictionary

Remove all items that match a condition in IDictionary


I'm trying to remove all elements in a IDictionary object that match a condition.

E.g. the IDictionary contains a set of keys and corresponding values (let say 80 objects). The keys are strings, the values could be of different types (think extracting metadata from a wtv file using directshow).

Some of the keys contains the text "thumb", e.g. thumbsize, startthumbdate etc. I want to remove all objects from the IDictionary who's keys contain the word thumb.

The only way I'm seeing here is to manually specify each key name using the .Remove method.

Is there some way to get all the objects who's keys contain the word thumb and them remove them from the IDictionary object.

The code looks like this:

IDictionary sourceAttrs = editor.GetAttributes();

GetAttributes is defined as:

public abstract IDictionary GetAttributes();

I don't have control over GetAttributes, it's returns an IDictionary object, I only know the contents by looking at it while debugging. (likely a HashTable)

UPDATE: Final Answer thanks to Tim:

sourceAttrs = sourceAttrs.Keys.Cast<string>()
                 .Where(key => key.IndexOf("thumb", StringComparison.CurrentCultureIgnoreCase) == -1)
                 .ToDictionary(key => key, key => sourceAttrs[key]);

Solution

  • So you want to remove all entries where the key contains a sub-string.

    You can use LINQ by keeping all that does not contain it:

    dict = dict
      .Where(kv => !kv.Key.Contains("thumb"))
      .ToDictionary(kv => kv.Key, kv => kv.Value);
    

    If you want a case-insensitive comparison you can use IndexOf:

    dict = dict
      .Where(kv => kv.Key.IndexOf("thumb", StringComparison.CurrentCultureIgnoreCase) == -1)
      .ToDictionary(kv => kv.Key, kv => kv.Value);
    

    Update according to your non-generic edit:

    If it's a non-generic dictionary like a HashTable you cannot use LINQ directly, but if you know that the key is a string you could use following query:

    // sample IDictionary with an old Hashtable
    System.Collections.IDictionary sourceAttrs = new System.Collections.Hashtable
    { 
        {"athumB", "foo1"},
        {"other", "foo2"}
    };
    
    Dictionary<string, object> newGenericDict = sourceAttrs.Keys.Cast<string>()
        .Where(key => !key.Contains("thumb"))
        .ToDictionary(key => key, key => sourceAttrs[key]);
    

    But maybe it's actually a generic Dictionary, you can try-cast with the as operator:

    var dict = sourceAttrs as Dictionary<string, object>;
    

    It's null if the cast didn't work.