Case-insensitive map?

1,034 views
Skip to first unread message

C. Florian Ebeling

unread,
Jan 18, 2010, 4:27:50 AM1/18/10
to clo...@googlegroups.com
Is there a good way to make a map case-insensitive for string keys? I
first thought just wrapping some function around it would be it, but
when I try it, it is really a bit more involved. Has anyone done this,
or is there a recommended way?

Florian

--
Florian Ebeling
florian...@gmail.com

Laurent PETIT

unread,
Jan 18, 2010, 7:59:22 AM1/18/10
to clo...@googlegroups.com
There's a library in clojure.contrib which allows to create your own
getters / setters for maps :

http://richhickey.github.com/clojure-contrib/fnmap-api.html

HTH,

--
Laurent

2010/1/18 C. Florian Ebeling <florian...@gmail.com>:

> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@googlegroups.com
> Note that posts from new members are moderated - please be patient with your first post.
> To unsubscribe from this group, send email to
> clojure+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
>

Richard Newman

unread,
Jan 18, 2010, 12:58:36 PM1/18/10
to clo...@googlegroups.com
> Is there a good way to make a map case-insensitive for string keys? I
> first thought just wrapping some function around it would be it, but
> when I try it, it is really a bit more involved. Has anyone done this,
> or is there a recommended way?

Do you want real case-insensitivity (i.e., you preserve the case of
some item in the map), or just down-casing?

To do that you need to alter the hashing and equality functions of the
map.

I have a Java implementation of a DowncaseMap which downcases String
keys (and thus avoids specifying the hash function), but obviously the
output is lowercase. I'm happy to share.

C. Florian Ebeling

unread,
Jan 18, 2010, 5:00:30 PM1/18/10
to clo...@googlegroups.com
>> Is there a good way to make a map case-insensitive for string keys? I
>> first thought just wrapping some function around it would be it, but
>> when I try it, it is really a bit more involved. Has anyone done this,
>> or is there a recommended way?
>
> Do you want real case-insensitivity (i.e., you preserve the case of some
> item in the map), or just down-casing?
>
> To do that you need to alter the hashing and equality functions of the map.

Yes, good point. I think the reasonable thing to do is downcasing for
my application.


> I have a Java implementation of a DowncaseMap which downcases String keys
> (and thus avoids specifying the hash function), but obviously the output is
> lowercase. I'm happy to share.

Thanks for the offer :) But I don't really want to resort to Java. I
was hoping for something transparant, but I realize now the
implications.

pmf

unread,
Jan 18, 2010, 5:22:23 PM1/18/10
to Clojure
On Jan 18, 1:59 pm, Laurent PETIT <laurent.pe...@gmail.com> wrote:
> There's a library in clojure.contrib which allows to create your own
> getters / setters for maps :
>
> http://richhickey.github.com/clojure-contrib/fnmap-api.html

Not wanting to interrupt this thread, but this is amazing! I could
have used this a dozen of times in the past few months. Thanks for
pointing this out!

Howard Lewis Ship

unread,
Jan 18, 2010, 9:15:41 PM1/18/10
to clo...@googlegroups.com
Tapestry 5 includes a case-insenstive Map and the basic idea can be
adapted. It was important to that code base that the case of keys be
kept, but that lookup by key be case insensitive. The hash code is
based on a case normalized version of the true key, and comparisons
are based on equalsIgnoreCase().

I haven't looked at how hard this would be to implement in Clojure; it
would be nice if there was those features (let me specify how to hash
keys, let me specify how to compare keys).

> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@googlegroups.com
> Note that posts from new members are moderated - please be patient with your first post.
> To unsubscribe from this group, send email to
> clojure+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
>

--
Howard M. Lewis Ship

Creator of Apache Tapestry

The source for Tapestry training, mentoring and support. Contact me to
learn how I can get you up and productive in Tapestry fast!

(971) 678-5210
http://howardlewisship.com

Richard Newman

unread,
Jan 18, 2010, 9:37:36 PM1/18/10
to clo...@googlegroups.com
> I haven't looked at how hard this would be to implement in Clojure; it
> would be nice if there was those features (let me specify how to hash
> keys, let me specify how to compare keys).

PersistentHashMap calls Util.hash(key), which calls key.hashCode().

You could use fnmap to replace input Strings with a
CaseInsensitiveString implementation that does hashing and comparison
case-insensitively...

Otherwise you'd probably need to subclass PHM and reimplement any
method that calls Util.hash.

C. Florian Ebeling

unread,
Jan 21, 2010, 5:01:28 AM1/21/10
to clo...@googlegroups.com
> There's a library in clojure.contrib which allows to create your own
> getters / setters for maps :
>
> http://richhickey.github.com/clojure-contrib/fnmap-api.html

This is actually a very cool approach and it fits my ideas quite well.
The only problem I have with it is that it constructs a whole new map
from keyvals. That sounds a bit expensive. Maybe it is possible do
something similar which just wraps over an existing map. I see if I
can come up with something like that. I understand that this doesn't
guarantee my the consistency within the map as I get it from having
all insertions done through the same setter. But in a case where one
just wants some transformation relying on the getter, that doesn't
matter.

Anyway, thanks for the pointer to this lib!

--
Florian Ebeling
florian...@gmail.com

Meikel Brandmeyer

unread,
Jan 21, 2010, 7:17:18 AM1/21/10
to Clojure
Hi,

On Jan 21, 11:01 am, "C. Florian Ebeling" <florian.ebel...@gmail.com>
wrote:

> This is actually a very cool approach and it fits my ideas quite well.
> The only problem I have with it is that it constructs a whole new map

> from keyvals. Maybe it is possible do something similar which just wraps
> over an existing map.

I think you misread the source of fnmap. Of course it creates a new
map in the beginning just as hash-map does. Then assoc/dissoc/etc.
just delegates to the underlying map with the appropriate fiddling
with the setter/getter.

If you already have a map you can do something like:

(require '[clojure.contrib.fnmap.PersistentMap :as fnmap])

(defn to-fnmap
[the-map setter getter]
(clojure.contrib.fnmap.PersistentFnMap. (assoc the-map ::fnmap/
setter setter ::fnamp/getter getter)))

> That sounds a bit expensive.

Did you try? "sounds" is not the best advisor.

Sincerely
Meikel

C. Florian Ebeling

unread,
Jan 21, 2010, 8:36:34 AM1/21/10
to clo...@googlegroups.com
> I think you misread the source of fnmap. Of course it creates a new
> map in the beginning just as hash-map does. Then assoc/dissoc/etc.
> just delegates to the underlying map with the appropriate fiddling
> with the setter/getter.
>
> If you already have a map you can do something like:
>
> (require '[clojure.contrib.fnmap.PersistentMap :as fnmap])
>
> (defn to-fnmap
>  [the-map setter getter]
>  (clojure.contrib.fnmap.PersistentFnMap. (assoc the-map ::fnmap/
> setter setter ::fnamp/getter getter)))

I didn't read the code as thoroughly as you did. Thanks for pointing
out this approach. It would make a nice addition to the exposed API.

--
Florian Ebeling
florian...@gmail.com

Reply all
Reply to author
Forward
0 new messages