MultiMap with Collection<String> - java

I am working on an XML file. In my XML file, there are somes nodes which have childs. This XML file has multiple tags.
<Cat categorie="CAT 1" guid="e9fdsd8ff">
<!--Electric energie management-->
**<item Var="VAR1" guid="2795ddsd410d">
<desc> Energie Smart Management
</desc>
<App guid="240adsqsd" />
<App guid="90dqddqsq" />**
</item>
</Cat>
Like you can see, my node "item " has the argument VAR=var1 and has 2 childs.
So I created a hashMap to put, for 1 node his childs like below
private Map<String, Collection <String >> multiMap = new HashMap <> ();
So I Have something like that actually : [Key=Var1, Value = [gui0,guid1,...]]
Now, I would like to know if you knew how to verify if a guid is contained in a collection associated with a key in order to retrieve this key.
For example, if I have this String : 240adsqsd. I want to recover Var1.
Thanks for your help

It is possible.
Say you have the key myKey and you want to know if the string mySearchString is contained in the collection behind that key.
multiMap.get("myKey").contains("mySearchString");
It will return true if mySearchString equals (case sensitive) any object in the colelction.
You have to be careful though, the method contains on a collection uses the case sensitive equals method and will only work when they are 100% equal. So when your collection contains something like "MYSEARCHstring", it won't work, as well as "The sentence that contains mySearchString".
EDIT:
(Thanks Nikolas and Dici)
Here a more complete example how to achieve that.
String mySearchString = "mySearchString";
Map<String, Collection<String>> multiMap = new HashMap<>();
for (String key : multiMap.keySet()) {
if (multiMap.get(key) != null && multiMap.get(key).contains(mySearchString)) {
return key;
}
}
If you don't know the key, you have to iterate over your map, check if one of the collections contains the searched string and then, when you found the collection (and its key) return the key.

A test without map modification would be:
boolean contained = multiMap.getOrDefault(key, Collections.emptyList()).contains(key);
Then there are Map.computeIfAbsent, computeIfPresent, merge if you want to update the map.

If I understand your question, you actually want to reverse your map because a map is good at accessing a value given a key not at finding a key given a value. Here's some pseudo-code to build the map:
map = new Map()
for item in items
for app in item.apps
map.put(app.guid, item.guid) // assuming guids are always unique
That would give you a Map<String, String> rather than Map<String, Collection<String>>. The former is good at telling you which item contains an application, the later is good at telling you which apps a given item contains. Given your reverse mapping map, you will be able to do the following:
// could just have Map<App, Item> appToItem if you build your map differently
// and App and Item define hashCode and equals
public boolean findVar(String appId, Map<String, String> appToItem, Map<String, Item> itemsById) {
Item item = itemsById.get(appToItem.get(appId));
if (item == null) return null;
return item.getVar();
}

Thank you to everyone for your answers.
If I understand correctly, it is preferable that I look for a value not his key.
So let's admit that I choose this option.
Can I recure each value for a key.
If my key is Var1 for example, would it be better for me to recover all its values?

Related

How Can I search a Integer in a TreeMap<String, List<Integer>>? [duplicate]

I'm checking to see if a key in my HashMap exists, if it does, I also want to check to see if any other keys have a value with the same name as that of the original key I checked for or not.
For example I have this.
System.out.println("What course do you want to search?");
String searchcourse = input.nextLine();
boolean coursefound = false;
if(hashmap.containsKey(searchcourse) == true){
coursefound = true;
}
This checks to see if the key exists in my hashmap, but now I need to check every single key's values for a specific value, in this case the string searchcourse.
Usually I would use a basic for loop to iterate through something like this, but it doesn't work with HashMaps. My values are also stored in a String ArrayList, if that helps.
You will want to look at each entry in the HashMap. This loop should check the contents of the ArrayList for your searchcourse and print out the key that contained the value.
for (Map.Entry<String,ArrayList> entries : hashmap.entrySet()) {
if (entries.getValue().contains(searchcourse)) {
System.out.println(entries.getKey() + " contains " + searchcourse);
}
}
Here are the relevant javadocs:
Map.Entry
HashMap entrySet method
ArrayList contains method
You can have a bi-directional map. E.g. you can have a Map<Value, Set<Key>> or MultiMap for the values to keys or you can use a bi-directional map which is planned to be added to Guava.
As I understand your question, the values in your Map are List<String>. That is, your Map is declares as Map<String, List<String>>. If so:
for (List<String> listOfStrings : myMap.values()) [
if (listOfStrings .contains(searchcourse) {
// do something
}
}
If the values are just Strings, i.e. the Map is a Map<String, String>, then #Matt has the simple answer.

Get total for unique items from Map in java

I currently have a map which stores the following information:
Map<String,String> animals= new HashMap<String,String>();
animals.put("cat","50");
animals.put("bat","38");
animals.put("dog","19");
animals.put("cat","31");
animals.put("cat","34");
animals.put("bat","1");
animals.put("dog","34");
animals.put("cat","55");
I want to create a new map with total for unique items in the above map. So in the above sample, count for cat would be 170, count for bat would be 39 and so on.
I have tried using Set to find unique animal entries in the map, however, I am unable to get the total count for each unique entry
First, don't use String for arithmetic, use int or double (or BigInteger/BigDecimal, but that's probably overkill here). I'd suggest making your map a Map<String, Integer>.
Second, Map.put() will overwrite the previous value if the given key is already present in the map, so as #Guy points out your map actually only contains {cat:55, dog:34, bat:1}. You need to get the previous value somehow in order to preserve it.
The classic way (pre-Java-8) is like so:
public static void putOrUpdate(Map<String, Integer> map, String key, int value) {
Integer previous = map.get(key);
if (previous != null) {
map.put(key, previous + value);
} else {
map.put(key, value);
}
}
Java 8 adds a number of useful methods to Map to make this pattern easier, like Map.merge() which does the put-or-update for you:
map.merge(key, value, (p, v) -> p + v);
You may also find that a multiset is a better data structure to use as it handles incrementing/decrementing for you; Guava provides a nice implementation.
As Guy said. Now you have one bat, one dog and one cat. Another 'put's will override your past values. For definition. Map stores key-value pairs where each key in map is unique. If you have to do it by map you can sum it just in time. For example, if you want to add another value for cat and you want to update it you can do it in this way:
animals.put("cat", animals.get("cat") + yourNewValue);
Your value for cat will be updated. This is for example where our numbers are float/int/long, not string as you have. If you have to do it by strings you can use in this case:
animals.put("cat", Integer.toString(Integer.parseInt(animals.get("cat")) + yourNewValue));
However, it's ugly. I'd recommend create
Map<String, Integer> animals = new HashMap<String, Integer>();

What Java data structure is best for two-way multi-value mapping

I'm relatively new to Java and I have a question about what type of data structure would be best for my case. I have a set of data which are essentially key-value pairs, however each value may correspond to multiple keys and each key may correspond to multiple values. A simplified example would be:
Red-Apple
Green-Apple
Red-Strawberry
Green-Grapes
Purple-Grapes
Considering the above example, I need to be able to return what color apples I have and/or what red fruits I have. The actual data will generated dynamically based upon an input file where each set will be anywhere from 100-100,000 values and each value may correspond to hundreds of values in the other set.
What would be the most efficient way to store and parse this data? I would prefer a solution as native to java as possible rather than something such as an external database.
This question is related, but I'm not sure how to apply the solution in my case given that I would need to assign multiple values to each key in both directions.
As you can't have duplicate keys in a Map, you can rather create a Map<Key, List<Value>>, or if you can, use Guava's Multimap.
Multimap<String, String> multimap = ArrayListMultimap.create();
multimap.put("Red", "Apple");
multimap.put("Red", "Strawberry");
System.out.println(multimap.get("Red")); // Prints - [Apple, Strawberry]
But the problem is you can't ask for the keys of a given object, I'll keep looking and make and edit if I find something else, hope it helps.
Still, you can make the reverse yourself by iterating the map and finding the keys for the object.
I suggest you use Guava's Table structure. Use color as your row keys and fruit as your column key or the other way round. Specifically, HashBasedTable is well suited for your case.
As per your use case, you wouldn't need to store anything for the values. However, these Tables don't allow null values. You could use a dummy Boolean or any other statistical useful value, i.e. date and time of insertion, user, number of color/fruit pairs, etc.
Table has the methods you need, such as column() and row(). Bear in mind that the docs say that these structures are optimized for row access. This might be OK for you if you plan to access by one key more than by the other.
You can create your own custom data structure
public class MultiValueHashMap<K, V> {
private HashMap<K, ArrayList<V>> multivalueHashMap = new HashMap<K, ArrayList<V>>();
public static void main(String[] args) {
MultiValueHashMap<String, String> multivaluemap = new MultiValueHashMap<String, String>();
multivaluemap.put("Red", "Apple");
multivaluemap.put("Green", "Apple");
multivaluemap.put("Red", "Strawberry");
multivaluemap.put("Green", "Grapes");
multivaluemap.put("Purple", "Grapes");
for(String k : multivaluemap.keySet()){
System.out.println(k + " : " + multivaluemap.get(k).toString());
}
}
public void put(K key, V value){
if (multivalueHashMap.containsKey(key)){
ArrayList<V> values = multivalueHashMap.get(key);
values.add(value);
}else{
ArrayList<V> values = new ArrayList<V>();
values.add(value);
multivalueHashMap.put(key, values);
}
}
public Set<K> keySet(){
return multivalueHashMap.keySet();
}
public ArrayList<V> get(K key){
return multivalueHashMap.get(key);
}
}
The output should be
Red : [Apple, Strawberry]
Purple : [Grapes]
Green : [Apple, Grapes]

How do I retrieve a key object from a Map?

Take two instances of the same class A, called foo and bar, where:
foo != bar
foo.equals(bar) == true
In other words, foo and bar are different instances but with the same hash code. Now take an instance of Map<A,B> called "map", where foo is a key in map. Is it possible to retrieve foo from Map, using bar? Currently I iterate through the key set and compare every key but is there a faster way? There don't seem to be any methods in Map for retrieving keys.
I am willing to try any data structure that implements Map or can work like a map.
Why do I want to do this? I'm trying to avoid retaining any more instances than necessary. Once I find foo I can release bar.
Thanks in advance...
You can use Apache Commons Collections ™. It has Bidirectional Maps BidiMap.
These represent maps where the key can lookup the value and the value can lookup the key with equal ease.
BidiMap bidi = new TreeBidiMap();
bidi.put("SIX", "6");
bidi.get("SIX"); // returns "6"
bidi.getKey("6"); // returns "SIX"
bidi.removeValue("6"); // removes the mapping
BidiMap inverse = bidi.inverseBidiMap(); // returns a map with keys and values swapped
See also
Commons Collections user guide
HashMap actually does have a method to retrieve the entry but it is package-private. I am not really sure why it isn't public to be honest. I don't think it exposes anything. You can, of course, call it with reflection.
Map<String, String> map = new HashMap<String, String>();
map.put(new String("hello"), "world!");
Method method = (
HashMap.class.getDeclaredMethod("getEntry", Object.class)
);
method.setAccessible(true);
#SuppressWarnings("unchecked")
Map.Entry<String, String> entry = (Map.Entry<String, String>)(
method.invoke(map, new String("hello"))
);
System.out.println(entry.toString().replace("=", " ")); // hello world
The reflection probably makes it not useful in the scenario you've described but I guess it could be useful to others. I wouldn't recommend using it.
Just using the existing map to find duplicztes doesn't seem to be enough. Use a second map, where you put(key,key) pairs. Then:
map.get(key) == null if the key is not already there
map.get(key) == firstObjectAllocated otherwise
This way may faster.
Iterator<A> mapKeyIterator=map.keySet().iterator();
while (mapKeyIterator.hasNext()){
A key;
if((key=mapKeyIterator.next()).equals(bar)) {
return key;
}
}
You can refer to the source code of HashMap
If based on your implementation:
foo.hashCode() == bar.hashCode() and foo.equals(bar)
Then, yes you could directly get the value for key foo by
map.get(bar)
updated: sorry misunderstanding your question before
if you want to keep the key, why you don't just keep the key cached. Then to retrieve the key is hash tree mapping, should be fast.
HashMap<K,V> map = new HashMap<K,V>();
HashMap<K,K> cacheKeys = new HashMap<K,K>();
cacheKeys.put(foo,foo);
map.put(foo,value);
//now you have var bar; you could retrieve the cached key
bar = cacheKeys.get(bar);//this will make bar = foo; the real bar will be gc
//then get the value
val = map.get(bar);

Remove a value from hashmap based on key [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
So, I have a HashMap<String, String>
public HashMap<String, String> frozen = new HashMap<String, String>();
and I want to remove a value from it depending on the key. So lets say I put in these
frozen.put("1", "1_1");
frozen.put("1", "1_2");
I want to remove only one of the values, not the whole keyset.
How would I go about doing this? If you still didn't understand, this non-existing method should explain it.
frozen.remove("1", "1_2");
Obviously that doesn't exist, but that's what I want.
Thanks in advance.
It seems the easiest solution would be to use some type of List as your value. In this particular case, it might look something like this:
final Map<String, List<String>> map = new HashMap<String, List<String>>();
final String key = "1";
map.put(key, new LinkedList<String>());
map.get(key).add("1_1");
map.get(key).add("1_2");
And then to remove a value given a particular key (as shown in your question), you may try something like map.get(key).remove("1_2");
You probably have put's parameter order inverted. Duplicate keys are not allowed. New values (for the same key) replace the older. So,
frozen.put("1", "1_1");
frozen.put("1", "1_2");
produces a map with only one entry: key="1", and value="1_2". On the contrary,
frozen.put("1_1", "1" );
frozen.put("1_2", "1" );
produces a map with 2 entries. To remove an entry, you only need to reference its key, as they are unique:
frozen.remove("1_2");
If this doesn't ring a bell, then please be more specific in what the data structure should hold, and what not. A few use cases would help.
What you are doing is not possible. You cannot put in a different value using the same key. You can remove an entry using the remove method, but for something you want, you can checkout something like Guava's MultiMap.
If you really want to remove based on a value, you'll need to iterate through the values of the Map using entrySet(), and then based on the value call the remove method using the found key.
The easiest way to find a solution to such a problem is to consult the JavaDocs: http://docs.oracle.com/javase/7/docs/api/
Find your class there (in your case: java.util.HashMap) and look for the remove method. In this case, you do not need to hand the value to the method (that would be really inefficient). To remove something from a HashMap, simply hand the key to the remove method:
frozen.remove("1");
This will remove the key-value pair "1", "1_2" from the HashMap.
Why will this not remove the first key-value pair? Because the put method overwrites any previous values. To be able to map a key to multiple values, try creating a HashMap with a String and a List:
HashMap<String, ArrayList> frozen = new HashMap<String, ArrayList>();
is a possible example.
I believe you're trying to map multiple strings to one key. It's possible but if you map your key to a List.
public Map<String, List<String>> frozen = new HashMap<String, List<String>>();
Then you can add multiple values to the same key as
public void addToMappedList(Map<String, List<String>> map,
String key, String value) {
List<String> existingValues = map.get(key);
if (existingValues == null) {
existingValues = new ArrayList<String>();
map.put(key, existingValues);
}
existingValues.add(value);
}
addToMappedList(frozen, "1", "1_1");
addToMappedList(frozen, "1", "1_2");
Here's how to go about removing individual values from the List. The boolean returned would indicate if the value was actually found and removed from the List or not.
public boolean removeFromMappedList(Map<String, List<String>> map,
String key, String value) {
List<String> existingValues = map.get(key);
if (existingValues != null) {
return existingValues.remove(value);
}
return false;
}
removeFromMappedList(frozen, "1", "1_1"); // true
removeFromMappedList(frozen, "1", "1_3"); // false
To remove the whole key and the List associated with it just use the Map directly
frozen.remove("1");

Categories