tags:

views:

363

answers:

3

I've got a whole host of values stored in a .net 2.0 hashtable. What I would really like to find is a way to, essentially, do a SQL select statement on the table.

Meaning, I'd like to get a list of keys whose associated values match a very simple text pattern (along the lines of "starts with a number".)

The final goal will be to remove these records from the hashtable for further processing.

I've been beating my head against this for a while now, and I can't seem to come up with anything.

Any ideas?

(On the off chance this matters: due to the realities of this project, any 3rd party widgets or upgrading to a more recent version of .net are off the table.)

+2  A: 

You could use a regex against every key in the hashtable. This is very dirty but it works:

    static void Main(string[] args)
    {
        Hashtable myhashtable = new Hashtable();
        myhashtable.Add("Teststring", "Hello");
        myhashtable.Add("1TestString1", "World");
        myhashtable.Add("2TestString2", "Test");

        List<String> newht = new List<String>;

        //match all strings with a number at the front
        Regex rx = new Regex("^[1-9]");
        foreach (string key in myhashtable.Keys)
        {
            if (rx.IsMatch(key) == true)
            {
                newht.Add(key);
            }
        }

        //Loop through all the keys in the new collection and remove them from
        //them from the main hashtable.
        foreach (string key in newht)
        {
            myhashtable.Remove(key);
        }
    }

EDIT: And just for fun, here is the LINQ version (sorry I just had too).

            Hashtable myhashtable = new Hashtable();
            myhashtable.Add("Teststring", "Hello");
            myhashtable.Add("1TestString1", "World");
            myhashtable.Add("2TestString2", "Test");

            Regex rx = new Regex("^[1-9]");
            var k = (from string key in myhashtable.Keys
                     where rx.IsMatch(key)
                     select key).ToList();

            k.ForEach(s => myhashtable.Remove(s));

EDIT: I have just added list of sting rather then a hashtable, I couldn't remember which .net version had generic lists in it ***slaps forehead

Nathan W
That's what I would suggest for his circumstances too.
Timothy Khouri
When I first saw the questions I was like "Yes! LINQ time" then I saw .net 2.0 then it was :'(, back using foreach loops again lol
Nathan W
This is going to be exhibit one in our quest to upgrade this system to .net 3.5. ;)
Electrons_Ahoy
+3  A: 

If you are truly looking for things that start with a number, then you can do it much faster than with a Regex. Just look at the first character of each key and determine if it is a digit. Store the keys you want to remove in a List since you only need to keep the key.

    List<string> keysToRemove = new List<string>( myhashtable.Count );
    foreach (string key in myhashtable.Keys)
    {
        if (char.IsDigit(key[0])
        {
            keysToRemove.Add(key);
        }
    }

    foreach (string key in keysToRemove)
    {
        myhashtable.Remove(key);
    }
tvanfosson
+1. Thats true but if you need to match anything else then a regex with work.
Nathan W
@Nathan. Agreed. Regex is a more general solution but you pay for the generality with extra overhead.
tvanfosson
@tvanfosson of course I totally agree.
Nathan W
+1  A: 

Using LINQ:

Dim myhashtable As New Hashtable
    myhashtable.Add("Teststring", "Hello")
    myhashtable.Add("1TestString1", "World")
    myhashtable.Add("2TestString2", "Test")

For Each i As String In From Element In myhashtable.Cast(Of DictionaryEntry)() Let k = DirectCast(Element.Value, String) Where k.StartsWith("W") Select DirectCast(Element.Key, String)
        MsgBox("This key has a matching value:" & i)
    Next

But better of using Dictionary if using LINQ:

    Dim d = New Dictionary(Of String, String)()
    d.Add("Teststring", "Hello")
    d.Add("1TestString1", "World")
    d.Add("2TestString2", "Test")

    For Each i As String In From element In d Where element.Value.StartsWith("W") Select element.Key
        MsgBox("This key has a matching value:" & i)
    Next

And instead of .StartsWith("W") you can of course do any other filtering you want.

Stefan
I don't know if doing a LINQ query in the foreach is such a good idea, because I'm pretty sure it will get run on every iteration. Not good for performance.
Nathan W
plus it's a absolute bitch to read.
Nathan W
That would be a bummer, I have done it like that everywhere in a recent project. Can you confirm this for sure?
Stefan
"plus it's a absolute bitch to read."I sort of agree, but I hate to have to declare a variable just to temporary store it when I can use it direct.
Stefan
I think i will ask a question about this linq-issue to be sure if its get run on every iteration...
Stefan
@Stefan one variable vs less-readability. Just personally I think one variable is better, plus then if you need to do something else with it later you can.
Nathan W
@Nathan this is so new for me so I havent really thought on how to use it in best manner yet. I agree with your points.btw i started a question about the iteration-thing.http://stackoverflow.com/questions/332864/does-this-linq-query-runs-on-every-iteration-of-the-for-each-loop
Stefan
@Stefan Thats cool, Sweet as, if you weren't I was going to :).
Nathan W