Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Java > Question about HashMap and Map.Entry ...

Reply
Thread Tools

Question about HashMap and Map.Entry ...

 
 
Andreas Leitgeb
Guest
Posts: n/a
 
      08-30-2012
Given a (Hash)Map<Long,Long> map and two Long values k and v,
Some task is to see if k is already in the map, and only if so,
then update the value in the map based on previous value and v.

Of course, that is trivial, and I've already implemented
it with containsKey(), get() and put().

It's just, that it seems to me that my piece of code
could be a bit *clearer*, if I could obtain the Map.Entry
for "k", and (if that isn't null) do getValue() and
setValue(...) on the Entry.

What I'm missing, however, is:
How would I get the Entry for a given key?
(apart from scanning all through the entrySet())

PS: using 1.6, but also interested in future (i.e. 1.7 or
even newer) prospects, and also in (any) explicit reasons
for *not* having some map.getEntry(K k).
Also, such an Entry should be tied to the Map just like
those in the entrySet(). NavigableMap has methods that
return Entries with "snapshot"-semantics, which is *not*
what I'm looking for.

 
Reply With Quote
 
 
 
 
markspace
Guest
Posts: n/a
 
      08-30-2012
On 8/30/2012 10:39 AM, Andreas Leitgeb wrote:

> What I'm missing, however, is:
> How would I get the Entry for a given key?



What about:

Long value = hashMap.get( key );
if( value != null )
hashMap.put( key , newValue );

This only updates the value for key if key is already present. I think
that's what you said you are doing. It assumes that "null" is not a
valid value for any key. (That can be changed as well, but it's
basically a scan through the entries at that point.)






 
Reply With Quote
 
 
 
 
Daniel Pitts
Guest
Posts: n/a
 
      08-30-2012
On 8/30/12 10:46 AM, markspace wrote:
> On 8/30/2012 10:39 AM, Andreas Leitgeb wrote:
>
>> What I'm missing, however, is:
>> How would I get the Entry for a given key?

>
>
> What about:
>
> Long value = hashMap.get( key );
> if( value != null )
> hashMap.put( key , newValue );
>
> This only updates the value for key if key is already present. I think
> that's what you said you are doing. It assumes that "null" is not a
> valid value for any key. (That can be changed as well, but it's
> basically a scan through the entries at that point.)


In theory, this does more work than it needs to, computing the hash
bucket twice, scanning any collisions on the key's buckets, etc... In
practice, this is fast enough for most operations.

I would like to suggest to the OP to look into Trove
<http://trove4j.sourceforge.net/>, which has support for primitive
collections (longs, rather than Longs), which may be much faster and
more memory efficient, depending on your use-cases.


 
Reply With Quote
 
Andreas Leitgeb
Guest
Posts: n/a
 
      08-30-2012
Daniel Pitts <(E-Mail Removed)> wrote:
> On 8/30/12 10:46 AM, markspace wrote:
>> On 8/30/2012 10:39 AM, Andreas Leitgeb wrote:
>>> What I'm missing, however, is:
>>> How would I get the Entry for a given key?

>> What about: [...] I think that's what you said you are doing.

You thought essentially right, markspace

> In theory, this does more work than it needs to, computing the hash
> bucket twice,...


That lets it look like I was caring for performance and
(premature, of course) optimization, which I've indeed
often a weakness for, but which isn't relevant for this
thread.

Let's say, I've got a method that takes an Map.Entry, and
the new value, and it updates the Entry's value accordingly.

So far I happened to use it for all keys in a Map, so
I iterated the entrySet, and called the method on each
loop-cycle.

Now, I'd rather call that method for specific keys, and
that's how I'd arrive at the outset of this thread.

My choice is now:
a) duplicating the method's code into one that operates
on the map directly for a key, or inlining the method's
code directly into the loop-body. (what I did)
b) creating an anonymous "implementation" of Map.Entry
with key&value, and writing the value back to the
map unconditionally afterwards. (I don't care about
eventually overwriting with same value)

but unfortunately not:
c) getting some darned Map-backed Entry just for that
darned key

> I would like to suggest to the OP to look into Trove <...>,
> which has support for primitive collections (longs, rather
> than Longs), which may be much faster and more memory efficient,
> depending on your use-cases.


If the TLongLongHashMap had a method to return a
java.util.Map.Entry<Long,Long>, then I'd be all for it

But it was still interesting to read about adjustOrPutValue(),
foreach*() and putIfAbsent() methods. These might come in handy some
time, and it's good to know, these trove collections offer stuff beyond
merely wrapping the primitives directly, compared to java.util.HashMap.

 
Reply With Quote
 
Andreas Leitgeb
Guest
Posts: n/a
 
      08-30-2012
Andreas Leitgeb <(E-Mail Removed)> wrote:
> b) creating an anonymous "implementation" of Map.Entry
> with key&value, and writing the value back to the
> map unconditionally afterwards. (I don't care about
> eventually overwriting with same value)


Damn, on re-read, I notice, that my own implementation of
Map.Entry could just hold a ref to the map and implement
setValue() to write the value back into the Map...

Maybe, even, the HashMap's entrySet()'s items even do that
for the Map-"backing". - I know, I could look into src.zip,
but probably won't.

 
Reply With Quote
 
Daniel Pitts
Guest
Posts: n/a
 
      08-30-2012
On 8/30/12 12:32 PM, Andreas Leitgeb wrote:
> Andreas Leitgeb <(E-Mail Removed)> wrote:
>> b) creating an anonymous "implementation" of Map.Entry
>> with key&value, and writing the value back to the
>> map unconditionally afterwards. (I don't care about
>> eventually overwriting with same value)

>
> Damn, on re-read, I notice, that my own implementation of
> Map.Entry could just hold a ref to the map and implement
> setValue() to write the value back into the Map...
>
> Maybe, even, the HashMap's entrySet()'s items even do that
> for the Map-"backing". - I know, I could look into src.zip,
> but probably won't.
>

Or, if you know all the keys before hand, you can use instead Map<Long,
MyLongWrapper> map.

MyLongWrapper would have .set() and .get(), or even .actUpon() depending
on the semantics you need.

Again, I suggest Trove, I seem to recall they had an interface that
supported exactly what you are trying to accomplish.
 
Reply With Quote
 
Lew
Guest
Posts: n/a
 
      08-30-2012
Andreas Leitgeb wrote:
> Given a (Hash)Map<Long,Long> map and two Long values k and v,
> Some task is to see if k is already in the map, and only if so,
> then update the value in the map based on previous value and v.
>
> Of course, that is trivial, and I've already implemented
> it with containsKey(), get() and put().
> It's just, that it seems to me that my piece of code
> could be a bit *clearer*, if I could obtain the Map.Entry
> for "k", and (if that isn't null) do getValue() and
> setValue(...) on the Entry.


I dispute that that would be clearer. You'd be using part
of the inner and should-be-hidden machinery of the Map
to express what 'containsKey()' already directly and quite
clearly expresses.

Also, modifying an 'Entry' might be synonymous with, but
is not the same as "put the key and value in the Map",
which 'Map#put(K key, V value)" is.

> What I'm missing, however, is:
> How would I get the Entry for a given key?
> (apart from scanning all through the entrySet())


A quick scan of the Javadocs for 'Map.Entry' says, sorry, no.

> PS: using 1.6, but also interested in future (i.e. 1.7 or


Java 7 is not the future. It's the present. It's up to 7u7 already.
As of November 2012, a few short months away, Java 6 will be
the past.

> even newer) prospects, and also in (any) explicit reasons
> for *not* having some map.getEntry(K k).


Because 'Map' already has 'get(K k)'.

> Also, such an Entry should be tied to the Map just like
> those in the entrySet(). NavigableMap has methods that
> return Entries with "snapshot"-semantics, which is *not*
> what I'm looking for.


A quick scan of the Javadocs for 'Map.Entry' says, sorry, no.
"The only way to obtain a reference to a map entry is from the iterator
of this collection-view. These Map.Entry objects are valid only for the
duration of the iteration; more formally, the behavior of a map entry
is undefined if the backing map has been modified after the entry was
returned by the iterator, except through the setValue operation on the
map entry."

"V setValue(V value) ... (optional operation)."

--
Lew
 
Reply With Quote
 
markspace
Guest
Posts: n/a
 
      08-30-2012
On 8/30/2012 12:24 PM, Andreas Leitgeb wrote:
> Daniel Pitts <(E-Mail Removed)> wrote:
>> On 8/30/12 10:46 AM, markspace wrote:
>>> On 8/30/2012 10:39 AM, Andreas Leitgeb wrote:
>>>> What I'm missing, however, is:
>>>> How would I get the Entry for a given key?
>>> What about: [...] I think that's what you said you are doing.

> You thought essentially right, markspace
>


OK...

>
> Let's say, I've got a method that takes an Map.Entry, and
> the new value, and it updates the Entry's value accordingly.
>

....
>
> Now, I'd rather call that method for specific keys, and
> that's how I'd arrive at the outset of this thread.



I think Lew has the correct analysis. I was going more on gut instinct
rather than analyzing carefully, but I don't see what is better, or more
clear, or more desirable about your method, compared to the code I posted.

I think it would help if you actually posted your code. I really can't
fathom the use case for this, and English prose descriptions aren't
helping. I can barely understand what it is you are doing to implement
this. The "why" of it is completely beyond me. Maybe some code will
spark some kind of idea for improvement....



 
Reply With Quote
 
markspace
Guest
Posts: n/a
 
      08-30-2012
On 8/30/2012 12:24 PM, Andreas Leitgeb wrote:
> Daniel Pitts <(E-Mail Removed)> wrote:
>> On 8/30/12 10:46 AM, markspace wrote:
>>> On 8/30/2012 10:39 AM, Andreas Leitgeb wrote:
>>>> What I'm missing, however, is:
>>>> How would I get the Entry for a given key?
>>> What about: [...] I think that's what you said you are doing.

> You thought essentially right, markspace
>


OK...

>
> Let's say, I've got a method that takes an Map.Entry, and
> the new value, and it updates the Entry's value accordingly.
>

....
>
> Now, I'd rather call that method for specific keys, and
> that's how I'd arrive at the outset of this thread.



I think Lew has the correct analysis. I was going more on gut instinct
rather than analyzing carefully, but I don't see what is better, or more
clear, or more desirable about your method, compared to the code I posted.

I think it would help if you actually posted your code. I really can't
fathom the use case for this, and English prose descriptions aren't
helping. I can barely understand what it is you are doing to implement
this. The "why" of it is completely beyond me. Maybe some code will
spark some kind of idea for improvement....



 
Reply With Quote
 
Andreas Leitgeb
Guest
Posts: n/a
 
      08-30-2012
Daniel Pitts <(E-Mail Removed)> wrote:
> On 8/30/12 12:32 PM, Andreas Leitgeb wrote:
>> Damn, on re-read, I notice, that my own implementation of
>> Map.Entry could just hold a ref to the map and implement
>> setValue() to write the value back into the Map...

> Or, if you know all the keys before hand, you can use instead Map<Long,
> MyLongWrapper> map.


I know all the relevant keys before hand. I currently do
an initial map.put(k,0L) for each relevant "k".

> MyLongWrapper would have .set() and .get(), or even .actUpon()
> depending on the semantics you need.


Indeed, that is a more elegant approach, than mine.
Although it won't save me the extra containsKey(), as I'll
be also having "k"s that aren't in the map, I'll turn my
auxiliary Entry-taking method from the outer class into a
method of some inner class MyLongWrapper that only needs
the extra "v" as parameter...

> Again, I suggest Trove, I seem to recall they had an interface that
> supported exactly what you are trying to accomplish.


Yep, they seem to have inspired your suggestion, but now
that I know it, I don't actually need TLong*HashMap
anymore. (My processing on the values is none of these
trove-predefined ones, anyway)

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
reuse HashMap$Entry (or HashMap in total) to avoid millions of allocations Vince Darley Java 4 03-02-2010 07:48 AM
java.util.Properties extending from HashMap<Object, Object> insteadof HashMap<String, String> Rakesh Java 10 04-08-2008 04:22 AM
a HashMap question Shawn Java 2 09-11-2006 06:16 PM
New to Java-Question About HashMap JR Java 4 10-10-2004 03:24 PM
HashMap implementation question hal@no_spam_statsbiblioteket.dk Java 3 07-08-2004 12:31 AM



Advertisments