Is there any way to use map or any other collection which allow us to store duplicate keys
with different values...
rather then using a List to store multiple values for same key?
Use Google Guava's MultiMap. This allows multiple values with single key
http://guava-libraries.googlecode.com/svn/tags/release03/javadoc/com/google/common/collect/Multimap.html
Map doesn't allow you to have duplicated keys. That even doesn't make sense.
Possible solution is having list(Collection) of values. Just go for it.If anything stopping you, let us know.
There is a Multimap concept. For example in guava. Multimap in guava
But it's not a part of Collection framework.
If you would not like signature like this Map<String, List<Item>>, you could easily wrap it with object. E.g.
class Items {
private List<Item> items;
public void add(Item i) {}
}
Of course it would not be possible to add items through map instance as map.add("key", item)
What about the next?:
Map<String, List<String>> map = new HashMap<>();
Add values
// add "key1" and "value1"
if (!map.containsKey("key1")) {
map.put("key1", new ArrayList<String>());
}
map.get("key1").add("value1");
// add "key1" and "value2"
if (!map.containsKey("key1")) {
map.put("key1", new ArrayList<String>());
}
map.get("key1").add("value2");
Get values
List<String> values = map.get("key1");
This with string, but can be for any type. And you don't need additional libraries.
you can use MultiMap from apache commons collections
http://commons.apache.org/proper/commons-collections/javadocs/api-3.2.1/org/apache/commons/collections/MultiMap.html
Related
I have an ArrayList of Objects. The object has five fields: id, date, name, value, adjusted_value. The list may hold multiple entries with the same name, and I am having trouble devising an efficient way to condense the list based on the name to where I will a list of similar objects but the values stored will be name, sum(value), sum(adjusted_value).
Is there an efficient way to do this? My current method has for loops inside of a do-while.
Clarfication:
I have a list of obejcts :
{id,date,name,value,ajusted_value},
{1,"10/30/2014","peaches",4,3}
{2,"10/30/2014","apples",2,2}
{3,"10/31/2014","peaches",3,1}
.
.
.
I want to condense to list based the name value to one that looks like this:
{null,null,"peaches",7,4}
{null,null,"apples",2,2}
.
.
.
However, I found that HashMap's put() functionality will perform what I desire automatically, but now I need to do this sort of action in Javascript if possible.
You can define a Map where the key is the name and value is the object instance.
Go through the list and for each instance check whether it exists in the map.
If not just add to the map. map.put(instance.name,instance)
If it's already added to the map just
mapInstance=map.get(instance.name);
mapInstance.value+=instance.value;
mapInstance.adjusted_value+=instance.adjusted_value;
After the loop you have the filled map with grouped data
I would use Guava in two step. Use a NameFunction to convert the list to a Multimap. Use a CondenseFunction to convert the values of the Multimap.
Function<MyClass, String> toName = new Function(){
public String apply(MyClass input){return input.name;}};
ImmutableListMultimap<String, MyClass> multimap = Multimaps.index(myList, toName);
Map<String, Collection<MyClass>> map = multimap.asMap();
Function<Collection<MyClass>, MyClass> condense= new Function(){
public MyClass apply(Collection<MyClass>input){
// create sums here
}};
Map<String, MyClass> condensed = Maps.transformValues(map, condense);
Collection<MyClass> result = condensed.getValues();
Multimaps.index()
Maps.transformValues
The question is pretty much self-explanatory. I have a data structure (I mentioned a HashMap but it could be a Set or a List also) which I initially populate:
Map<String, String> map = new HashMap<String, String>();
for( something ) {
map.put( something );
}
After the structure has been populated, I never want to add or delete any items:
map.freeze();
How could one achieve this using standard Java libraries?
The best you can do with standard JDK libraries is Collections.unmodifiableMap().
Note that you must drop the original map reference, because that reference can still be accessed and changed normally. If you passed the old reference to any other objects, they still will be able to change your map.
Best practice:
map = Collections.unmodifiableMap(map);
and make sure you didn't share the original map reference.
It sounds like you would do very well with Guava's ImmutableMap. Which allows use of the Builder pattern to assemble and "freeze".
Wrap it in a class and make it immutable. For example:
public class ImmutableMapWrapper {
private Map<String, String> map = new HashMap<String, String>();
public ImmutableMapWrapper() {
for( something ) {
this.map.put( something );
}
}
}
Create an immutable HashMap:
HashMap <MyKey, MyValue> unmodifiableMap = Collections.unmodifiableMap(modifiableMap);
JavaDoc here.
Also, I think the Google data collections utils (Guava???) has an ImmutableMap type already.
I have something along the lines of this:
public HashMap<Boolean, String> map = new HashMap();
map.put(this.inverted, "Inverted");
map.put(this.active, "Loading");
System.out.println(map.size());
after seeing that the size was always 1, I realised that using map.put was overriding the previous data. I am currently trying to iterate over the hashmap. Is there a way to add mappings to it without overriding previous ones?
You have declared your HashMap as: -
public HashMap<Boolean, String> map = new HashMap();
Now, just think how many maximum mapping can you have in your map? The answer you can get by thinking of, what all values can your Boolean type take. This is because, you cannot have duplicate keys in a HashMap.
So, probably you got it now, that you can at max have only 2 mappings in your map, one for true and other for false(In fact you can have a 3rd one too, as you can have a mapping for a null key too in your HashMap).
So, in your case, if both this.inverted and this.active are either true or false. Then only one of them can be there, and that would be the later value inserted.
Is there a way to add mappings to it without overriding previous ones?
Probably you have build your HashMap wrongly. You should declare your map as: -
private Map<String, Boolean> map = new HashMap();
And now you can put two mappings as: -
map.put("Inverted", this.inverted);
map.put("Loading", this.active);
It's because this.inverted.equals(this.active) and this.inverted.hashcode()==this.active.hashcode()
Maybe you need redefine the equals method for the key.
In MAP
An object that maps keys to values. A map cannot contain duplicate keys; each key can map to at most one value. ---> from Map Api
from your implementation, may be this.inverted and this.active both have same value.
Check the input once. print the keySet, then check.
or change the input to Map<String, Boolean>
As #Frank suggest you should invert your Map.
public final Map<String, Boolean> map = new HashMap<>();
map.put("Inverted", this.inverted);
map.put("Loading", this.active);
System.out.println(map);
If the keys are the same than the previous value is overwritten in a standard Java Map. If you don't want this, you can have a look at a multimap which is implemented for example in commons-collections. It can hold different values for one key.
Hashmap is based on key/value pairs. If your keys are equal (they have the same hashcode), it will behave as you described.
For your use case, reversing your key/value pairs will help you.
public HashMap<String, Boolean> map = new HashMap();
map.put("Inverted", this.inverted);
map.put("Loading", this.active);
System.out.println(map.size());
Get object of innermap ,by passing outer map key .. Then check if key of innermap exists then update values with previous data. else create new object of inner map.
I've been given a test-driven development problem (I need to make it work based on the junit methods provided) based on implementing a HashMap that uses a strings for the keys and ArrayLists for the values. The key needs to be able to support one or more corresponding values. I need to set up my methods in a way that I can add or subtract values from the hash, and then see the updated contents of the hash. My struggle is taking info provided from the unit method shown below (exercising myClass and it's addingMethod method) methods) and getting it put properly into the hash.
void add() {
myClass = new MyClass("key1", "value1");
myClass.addingMethod("blargh", "blarghvalue");
myClass.addingMethod("blargh2", "uglystring");
myClass.addingMethod("blargh", "anotherstring");
//and so on and so on............
For my end result, when I print out the results of myClass, I need to see something like:
{blargh=[blarghvalue, anotherstring], blargh2=uglystring}
I need to be able to add to this, and remove values as well.
I'm very new to java collections (obviously). I can get things to work if they only have a 1 to 1 relationship, and the hashmap is 1:1. So a very simple addingMethod like this:
public void addingMethod(String key, String value) {
hashMap.put(key, value);
Will get a string string hashmap, but of course if I reuse a key with a new key-value pair, the original key-value gets stepped on and goes away. When it comes to working with hashmaps and arraylists dynamically though, and beyond a 1:1 key:value relationship, I'm lost.
It sounds like you need a MultiMap, which is provided by Google's great Guava libraries:
A collection similar to a Map, but which may associate multiple values with a single key. If you call put(K, V) twice, with the same key but different values, the multimap contains mappings from the key to both values.
What you need is Map<String, List<String>> and inside put check if entry exists if yes then add to list.
Declare your Map like below
Map<String, List<String>> map = new HashMap<String, List<String>>();
Note that syntax of adding Method should be same as put
public List<String> put(String key, String value) {
if (!map.containsKey(key)) {
return map.put(key, new ArrayList<String>());
}
List<String> list = map.get(key);
list.add(value);
return map.put(key, list);
}
I have map where each key is a String.
To access a value I can use the .get method of Map. If I want to return anything that matches the key for example : "one, onetwo, onetwothree" , get all values that contain the String "two" so in this case return "onetwo, onetwothree". Is this possible using a Map ?
Im currently using a List and iterating over each String and checking if the String contains the value I am searching for.
There is no such method on any of the Map classes (afaik). You can iterate the keys then check the containment of the fragment, or use a completely different data structure. A trie-map would do it I guess.
Edit:
What you currently doing should be just fine for 99% of all cases. If you are processing extreme amounts of data, use full text indexing. (Which can be done with Suffix trees)
Using a HashMap you will have to iterate over all keys and as soon as a key matches your pattern, then collect that value and keep going until you are done.
Using a TreeMap you can get the keys in sorted order so you could use perhaps this property for a more efficient search.
But I think you should switch to a different data structure. A trie as #zeller also points out seems to do what you want
as others said there are no methods in the java collections API to acheive this.
this is how you do it by iterating over keys of a map
HashMap<String, String> map = new HashMap<String, String>();
map.put("onesample", "1");
map.put("onetwo", "2");
map.put("onetwothree", "3");
for(Entry<String, String> en: map.entrySet()) {
if(en.getKey().contains("two")){
System.out.println(en.getKey());
}
}
}