Mike Keskinov
Mike Keskinov

Reputation: 11878

Get value in case-insensitive HashSet<string>

I have case-insensitive HashSet<string>:

private HashSet<string> a = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);

I'm curious if I can now extract the string in the actual case. Pseudo code of what I need:

return a.Contains(word) ? a[word] : null;

(just a pseudo code, it won't work)

For example, I have string "TestXxX" in the HashSet. I need for the code which gets "testxxx" (or "tEsTXXx") as input and returns "TestXxX".

My current workaround is to use Dictionary<string,string> instead and put the same value for both key and value. This is obviously not elegant and consumes 2x memory as it actually needs.

Upvotes: 6

Views: 2264

Answers (2)

user743382
user743382

Reputation:

HashSet<T> doesn't expose any functionality to achieve what you're looking for. If you don't need to use a HashSet, then Kirill Polishchuk's answer makes sense to me.

Otherwise, if you do need a HashSet, a somewhat nasty hack is to use a custom equality comparer. Create your own equality comparer that simply forwards all requests to StringComparer.InvariantCultureIgnoreCase, but caches the last-passed objects.

If you have that, then after a.Contains(word) returns true, the last-passed objects should be 1) word and 2) the word as it appears in a.

Strictly speaking, this is not guaranteed to work, since HashSet is allowed to call the comparer with different values than what you expect. It's certain to work in current versions of .NET Framework though and unlikely to break in the future: the comparer equality function obviously needs to be called with those arguments in order for Contains to return the correct value, and there is no reason why it would be called with any other arguments except to intentionally break code like this.

Upvotes: 0

Kirill Polishchuk
Kirill Polishchuk

Reputation: 56162

You can override KeyedCollection

public class Keyed : KeyedCollection<string, string>
{
    public Keyed(IEqualityComparer<string> comparer) : base(comparer)
    {

    }

    protected override string GetKeyForItem(string item)
    {
        return item;
    }
}

Then use it:

var keyed = new Keyed(StringComparer.InvariantCultureIgnoreCase);
keyed.Add("TestXxX");

Console.WriteLine(keyed["tEsTXXx"]);

Upvotes: 7

Related Questions