Generics for a multiplevalue hashmap


A

Alexis Berry

Hello,

I want to create a HashMap which has a list for each key. Therefore I can store more than one value for each key. (I know this breaks the true use of a hashmap but I want a datastruture that takes one key and hold multiple value)

I thought I would be able to define:

public class MultipleValueHashMap<T, java.util.List<U>> implements Map<T, java.util.List<U>> {

.....
}

I would then construct it by "new MultipleValueHashMap<Inteteger, List<String>()"

Unfortunately this does not compile. I think it might be because I am mixing generic types with real types. Am I correct?

Is there a way I can use a map to store more than one value and use generics?

Thanks
 
Ad

Advertisements

M

markspace

Unfortunately this does not compile. I think it might be because I am
mixing generic types with real types. Am I correct?


Sort of. You can't put constraints on the parameter type the way you
are thinking.

public class MultipleValueHashMap<T, java.util.List<U>> implements
Map<T, java.util.List<U>> {


Should be:

public class MultipleValueHashMap<T, U> implements
Map<T, java.util.List<U>> {

I think. I'll check it in a sec and post again if it needs correcting.
 
A

Arved Sandstrom

Hello,

I want to create a HashMap which has a list for each key. Therefore I can store more than one value for each key. (I know this breaks the true use of a hashmap but I want a datastruture that takes one key and hold multiple value)
Why does it break the "true use" of a hashmap? The use of a map or
dictionary or associative array - whatever you choose to call it - is to
relate a collection of keys and values such that each key is associated
with a value. That value may be anything, including a list or set of values.

As it happens a map which has lists or sets as values is a typical
implementation of a so-called multimap. Good multimap interfaces make
the implementation easier to use but don't hide it much. See the
Wikipedia entry on multimap for some references to implementations.

I won't address the rest of the post because others will already be all
over it. :)

AHS
 
A

Arne Vajhøj

I want to create a HashMap which has a list for each key. Therefore I can store more than one value for each key. (I know this breaks the true use of a hashmap but I want a datastruture that takes one key and hold multiple value)

I thought I would be able to define:

public class MultipleValueHashMap<T, java.util.List<U>> implements Map<T, java.util.List<U>> {

....
}

I would then construct it by "new MultipleValueHashMap<Inteteger, List<String>()"

Unfortunately this does not compile. I think it might be because I am mixing generic types with real types. Am I correct?

Is there a way I can use a map to store more than one value and use generics?

public class MM1<T,U> implements Map<T, List<U>> {
....
MM1<Integer,String> mm = new MM1<Integer,String>();

or

public class MM2<T,U> extends HashMap<T, List<U>> {
....
MM2<Integer,String> mm = new MM2<Integer,String>();

seems obvious to me.

Arne
 
E

Esmond Pitt

public class MultipleValueHashMap<T, java.util.List<U>> implements Map<T, java.util.List<U>> {

public class MultipleValueHashMap<T, <L extends java.util.List<U>>>
implements Map<T, L> ?
 
Ad

Advertisements

S

Stefan Ram

Alexis Berry said:
public class MultipleValueHashMap<T, java.util.List<U>> implements Map<T, java.util.List<U>> {

I'd just use:

Multimap<D,V>

. When you just implement Map, not HashMap, then why use
»Hash« in the name of the class?

Also, you do not want to implement the map interface, but
your custom interface, so why do you want to announce that
you implement Map via an « implements » clause at all?

D is the domain.

V is the type of the values.

add(d,v) adds the value v to the set of d

You need to decided whether you want a set or a bag.
When you use a bag, then »add(d,v);add(d,v);« will
increment the multiplicity of v by 2. If you use a
set, »add(d,v);add(d,v);« is the same as »add(d,v);«.

You could be more flexible with a delegate for the
collection:

class Multimap<D,V>
{ public Multimap( Container c, ... ){ ... } ... }

In this case

add(d,v)

will add v to the container of d (it will create a new
container, if such a container does not exist yet), using
the add method of this container, whatever this add method
does.
 
M

markspace

public class MultipleValueHashMap<T, <L extends java.util.List<U>>>
implements Map<T, L> ?


Well, this doesn't work for a couple of reasons. First, in terms of
syntax, you still have to declare U as a type parameter:

public class GenericTest<T, U, L extends List<U>>
extends AbstractMap<T, List<U>> {

Secondly, "List" here is both an input and and output. And going by
PECS -- Producer Extends, Consumer Super -- you can't use just one. So
I think the default is just to try to get the right type there (List
works) and be careful with your type declarations.
 
Ad

Advertisements

S

Stefan Ram

I'd just use:
Multimap<D,V>

For example:

public class Main
{
public static void main( final java.lang.String[] args )
{
final Multimap<java.lang.Integer,java.lang.Integer> m
= new DefaultSetMap<java.lang.Integer,java.lang.Integer>();
m.add( 1, 1 ); m.add( 2, 2 ); m.add( 2, 3 );
java.lang.System.out.println( m ); }}

This prints:

{1=[1], 2=[2, 3]}

Rest of the source code (I suggest to quote only parts one
directly refers to):

interface Container<V>
{ public void add( final V v );
public java.lang.String toString(); }

interface ContainerFactory<V>
{ public Container<V> newContainer(); }

class DefaultContainer<V> implements Container<V>
{ final java.util.Set<V> set;
public DefaultContainer()
{ this.set = new java.util.HashSet<V>(); }
public void add( final V v )
{ this.set.add( v ); }
public java.lang.String toString()
{ return this.set.toString(); }}

class DefaultContainerFactory<V> implements ContainerFactory<V>
{ public DefaultContainer<V> newContainer()
{ return new DefaultContainer<V>(); }}

interface Multimap<D,V>
{ public void add( final D d, final V v );
public java.lang.String toString(); }

class DefaultMultimap<D,V> implements Multimap<D,V>
{ final java.util.Map<D,Container<V>> map;
final ContainerFactory<V> containerFactory;
public DefaultMultimap
( final java.util.Map<D,Container<V>> map,
final ContainerFactory<V> containerFactory )
{ this.map = map;
this.containerFactory = containerFactory; }
public boolean exists( final D d ){ return this.map.containsKey( d ); }
public Container<V> get( final D d ){ return this.map.get( d ); }
public void set( final D d, final Container<V> v )
{ this.map.put( d, v ); }
public void add( final D d, final V v )
{ if( !this.exists( d ))this.set( d, this.containerFactory.newContainer() );
this.get( d ).add( v ); }
public java.lang.String toString()
{ return this.map.toString(); }}

class DefaultSetMap<D,V> implements Multimap<D,V>
{ final Multimap<D,V> multimap;
public DefaultSetMap()
{ this.multimap = new DefaultMultimap<D,V>
( new java.util.HashMap<D,Container<V>>(),
new DefaultContainerFactory<V>() ); }
public void add( final D d, final V v )
{ this.multimap.add( d, v ); }
public java.lang.String toString()
{ return this.multimap.toString(); }}

One can observe that DefaultMultimap<D,V> is defined without any
fixed container for the multiple values of a key. Such a container
is only added in DefaultSetMap<D,V>.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top