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>();
Related
I've created a TreeMap with products.
And I want to count the number of times they repeat themselves, but have no clue what to code. Any hints? (I expect no code, just suggestions)
private static Map<Integer, String> shoppingCart() {
Map<Integer, String> result = new TreeMap<>();
result.put(1, "sausage");
result.put(2, "sausage");
result.put(3, "soup");
result.put(4, "egg");
result.put(5, "egg");
result.put(6, "tomato");
result.put(7, "sausage");
return result;
}
I was thinking about adding a counting variable, but still it doesn't fix the repeating problem.
Maybe not the best approach, but without modifying what you already have, you could use another map to store the products as keys and the quantity as the value for those keys:
Map<Integer, String> result = shoppingCart();
Map<String, Integer> productQuantities = new HashMap<>();
result.values().forEach(value ->
productQuantities.put(value,productQuantities.getOrDefault(value, 0) + 1));
To print the resulting map:
productQuantities.forEach((key, value) -> System.out.println(key + ":" + value));
I created a TreeMap with products, and i want to count the number of times they repeat themselves
Probably a different type of Map with keys representing items and values representing the corresponding count would be more handy. Something like:
NavigableMap<String, Integer> countByItem
Note: in order to access methods of the TreeMap like ceilingKey(), floorKey(), higherEntry(), lowerEntry(), etc. which are not defined in the Map interface you need to use NavigableMap as a type.
And it might make sense to make the item to be a custom object, instead of being a String. That would guard you from making typo, and it provides a possibility to gives useful behavior to Item
public class Item {
private int id;
private String name;
// constructor, getters, equals/hashCode, ect.
}
That's how map of items can be updated using Java 8 method merge(), which expects a key, a value and a function responsible for merging the old value and the new one:
NavigableMap<Item, Integer> countByItem = new TreeMap<>(Comparator.comparingInt(Item::getId));
countByItem.merge(new Item(1, "sausage"),1, Integer::sum);
countByItem.merge(new Item(1, "sausage"),1, Integer::sum);
countByItem.merge(new Item(2, "soup"),1, Integer::sum);
If you don't feel very comfortable with Java 8 functions, instead of merge() you can use combination of methods put() & getOrDefault():
Item sausage = new Item(1, "sausage");
countByItem.put(sausage, countByItem.getOrDefault(sausage, 0) + 1);
I can only guess at your goal. In your Map <Integer, String>, what does the Integer represent? Product number? Quantity? Sequence number? Something else?
If the Integer represents quantity, you have it backwards. It should be Map <String, Integer>. In a Map<X,Y>, the X represents the key. A Map allows fast lookup by the key. The Y is the value -- the information you want to find for a particular key, if the key is in the Map.
For example, if you want to add "sausage", you want to check if it is in the Map. If it isn't, put it into the Map with quantity 1. If it is, retrieve it and update the quantity.
If the Integer represents a sequence number (1st item, 2nd item, 3rd item, ...), you don't need a Map. Consider using an array or a data structure that preserves order, such as a List.
However, using an array or List still leaves you with the problem of how find how many of each item are in the list, when duplicates are allowed, as they are in your problem. To solve that, consider a Map<String, Integer> where the Integer (map value) is the quantity, and the String (map key) is the product name.
If I were doing this, I'd create classes to allow me to glue together related information. Here is part of a hypothetical example, which might be more realistic than you need:
public class Product {
private int upc; // product code, often represented with bar code
private Decimal price;
private String description;
private String shortDescription;
private ProductClass prodClass; // department, taxable, etc.
// etc. -- add needed fields, or remove irrelevant
// constructors, getters, setters,
Override .equals and .hashcode in Product. You use the UPC for those.
If you use implements Comparable<Product>, you have the possibility of using binary search, or a search tree.
public class Receipt {
private Decimal total;
private Decimal taxableTotal;
private Map <Product,Integer> shoppingCart; // Product, Quantity
// etc.
When each item is scanned, you can lookup the Product in the Map, and add it if not found, or update the quantity if found, as in the previous answers.
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?
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.
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]
I want to write a program that prints out entries "0" and "4" of the HashMap (i.e. entry.getKey(0) and entry.getKey(4) but it won't let me do this) What would be another way using what I already have?
Basically I have this:
HashMap<String, Integer> hm = new HashMap<String, Integer>();
I can iterate over each entry using this code:
for (Map.Entry<String,Integer> entry : hm.entrySet())
{
System.out.println(entry.getKey() + "/" + entry.getValue());
}
Since people have asked for more contextual information, I am storing a set of strings in the HashMap. For example the 0th entry is "Bob", the 1st entry is "Mindy", the 2nd is "Yasser", the 3rd is "Greg" and the 4th is "Jacky." I want the program to print out the 0th and 4th entries of the populated HashMap.
If you are specific about the keys in the Map, you can directly use get() method.Like this,
Integer value = hm.get("0");
If you want to iterate then use something like the code below :
HashMap<String, Integer> hm = new HashMap<String, Integer>();
for (Entry<String, Integer> entry : hm.entrySet())
{
String key = entry.getKey();
if(key.equals("0") || key.equals("1"))
System.out.println(key + "/" + entry.getValue());
}
You cannot pass index to the getKey() method like getKey(0) etc. Refer the documentation.
HashMap class makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time. So, if you are looking to fetch values from a HashMap based on index, probably it is not possible. Closest to your requirement will be something like LinkedHashMap, which maintains the order of keys for insertion/access order.
HashMap works on principle of hashing, we have put(key, value) and get(key) method for storing and retrieving Objects from HashMap. When we pass Key and Value object to put() method on Java HashMap, HashMap implementation calls hashCode() method on Key object and applies returned hashcode() into its own hashing function to find a bucket location for storing Entry object, important point to mention is that HashMap in Java stores both key and value object as Map.Entry in bucket which is essential to understand the retrieving logic.
The HashMap has no defined ordering of keys. You may use LinkedHashMap instead of HashMap It will always return keys in same order (as insertion) when calling keySet(). And then you pick the 0th or 4th key.Later you can retrieve the value for the keys you fetched at 0th and 4th location.
I would recommend simply using the get() method with the provided key. Iteration is not necessary in this case.
Since people have asked for more contextual information, I am storing a set of strings in the HashMap. For example the 0th entry is "Bob", the 1st entry is "Mindy", the 2nd is "Yasser", the 3rd is "Greg" and the 4th is "Jacky." I want the program to print out the 0th and 4th entries of the populated HashMap.
With how it is being used, an HashMap makes no sense. Use a String[] instead!
String[] names = {"Bob", "Mindy", "Yasser", "Greg", "Jacky" };
System.out.println("When " + names[0] + " met " + names[4]);
Why not a targeted approach:
String[] targets = {"0", "4"};
for (String target : targets) {
System.out.println(target + "/" + hm.get(target));
}
Way more efficient than the "big hammer" full iteration approach, and you get output order for free.
If you have a lot of entries in your Map you may considerate to use one of the navigable collections, like TreeMap.
NavigableMap<String,String> map = new TreeMap<>()
map.subMap("0", true, "4", true);
Visit: http://docs.oracle.com/javase/6/docs/api/java/util/NavigableMap.html