I have a MultiMap that has multiple similar values:
{Entertainment=[5], Food=[2, 2, 2], Products=[11], Health & Beauty=[3]}
How do I count the total of these keys so that it counts as follows?
Entertainment = 1
Food = 3
Products = 1
Health & Beauty = 1
The number inside the array is the category id, so that Food has 3 occurrences.
Either multimap.get(key).size() or multimap.keys().count(key) should work.
Documentation
Assuming your map is declared as follows : MultiMap<String, Integer> map, you can do the following :
for (String key : map.keySet()) {
int count = map.get(key).size();
}
Using asMap(), you can get the Map<String, Collection<Integer>> representation of the Multimap, from which it's easy to get the count directly without multiple lookups:
for (Map.Entry<String, Collection<Integer>> entry : multimap.asMap().entrySet()) {
System.out.println(entry.getKey() + " = " + entry.getValue().size());
}
Note: to get the Set of keys on the Multimap, you need to call keySet(), not keys() (which indeeds repeats the key as many times as it has values).
Related
I am trying to build a simple program that in essence will return the key associated to the highest value in a nested Map. For example (below numbers are just an example, they are not real).
public class MultiValueMap {
public static void main(String[] args) {
Map<String, HashMap<String, Integer>> singers = new HashMap<>();
singers.put("Elvis", new HashMap<>());
singers.get("Elvis").put("All Shook up", 8);
singers.get("Elvis").put("Don't be Cruel", 5);
singers.get("Elvis").put("Viva las Vegas", 3);
}
}
The idea here is to get either the top song or lowest rated song. The program should return for example "All Shook Up" if I want the top rated song.
Any ideas on how to accomplish this?
Note that, given you want min and max a HashMap is not the most suitable structure.
You'll need to traverse over all values every time you want an answer to this question. If you use a TreeSet you can reduce that to a simple binary search on all keys.
record SongScore(String songName, int score) {}
....
Map<String, TreeSet<SongScore>> singers = new HashMap<>();
TreeSet<SongScore> songs = new TreeSet<>(Comparator.comparingInt(SongScore::score));
songs.add(new SongScore("All Shook up", 8));
songs.add(new SongScore("Don't be Cruel", 5));
songs.add(new SongScore("Viva las Vegas", 3));
singers.put("Elvis", songs);
var lowest = singers.values().stream().map(TreeSet::first).min(Comparator.comparingInt(SongScore::score));
var highest = singers.values().stream().map(TreeSet::last).max(Comparator.comparingInt(SongScore::score));
Given
Given your map with
singer_map: interpret -> title_map
title_map: title -> rating
like:
Map<String, HashMap<String, Integer>> singers = new HashMap<>();
singers.put("Elvis", new HashMap<>());
singers.get("Elvis").put("All Shook up", 8);
singers.get("Elvis").put("Don't be Cruel", 5);
singers.get("Elvis").put("Viva las Vegas", 3);
Algorithm
Now define a temporary entry variable for the favoriteTitle.
Take the title-map like Map<String, Integer> titles = singers.get("Elvis") and iterate over each entry (e.g. a for-each loop).
In the loop-body of each iteration:
If an entry is higher then favoriteTitle or favoriteTitle is empty, then store the current entry.
After the loop you have the favoriteTitle with highest rating for this singer. If the singer has no titles, then there is also no favorite.
What if all or the more than 1 highest rated titles have the same rating?
Sample code
Map<String, Integer> titles = singers.get("Elvis");
Map.Entry<String, Integer> favoriteTitle;
for (Map.Entry<String, Integer> t : titles) {
System.out.println(t.getKey() + " rated " + t.getValue());
if (favoriteTitle == null || favoriteTitle.getValue() < t.getValue()) {
favoriteTitle = t;
}
}
System.out.println("Favorite: " + favoriteTitle.getKey() + " rated " + favoriteTitle.getValue());
See also:
GeeksforGeeks: Map.Entry interface in Java with example, tutorial
In Java 8+ use a stream with Comparator like in Finding Key associated with max Value in a Java Map.
Using Java8 streams you can use a pretty simple one liner. This example assumes there is at least one entry in the map with a non-null value.
map.entrySet() // get all entries
.stream() // stream over them
.max(Comparator.comparingInt(Map.Entry::getValue)) // max over all entries by value (here: rating), comparing them as integers
.get().getKey() // get the entry, then the key (here: title)
I am trying to get first k values from a hashmap.
I know how to get all values from a hashmap and also how to iterate over all of them. Is there any short way to generate first k values from hashmap
for (Map.Entry<String, Integer> en : hmap.entrySet())
{
System.out.println("Key = " + en.getKey() + ", Value = " + en.getValue());
}
The notion of the first elements is undefined for Map interface. How it was mentioned in comments you can use LinkedHashMap or TreeMap where the first item make sense.
If you just want to get some limit number of map values, you could use stream api with limit:
hmap.entrySet().stream()
.limit(2)
.collect(Collectors.toList());
I have a list of some strings. I need to merge dublicates and add counter of duplicates. For example:
list1.add("Mom");
list1.add("Mom");
list1.add("Son");
list1.add("Son");
list1.add("Dad");
list1.add("Dad");
merge and add counter
and output needs to be like this:
Mom 2
Son 2
Dad 2
Also I need to sort this new list, but I think I can just use collections, to do that.
public static Map<String, Long> getValuesWithNumberOfOccurrences(
List<String> list) {
return list.stream()
.collect(
Collectors.groupingBy(i -> i, HashMap::new,
Collectors.counting()));
}
Use HashMap to keep duplicates:
HashMap<String, Integer> map = new HashMap<>();
for (int i = 0; i < list.size(); i++) {
String text = list.get(i);
if(map.get(text) == null) {
map.put(text, 1);
} else {
map.put(text, map.get(text) + 1);
}
}
for (String text : map.keySet()) {
System.out.println(text + " " + map.get(text));
}
I'm assuming that the output order needs to respect the order in which the keys were first encountered. Fortunately the clever Java bods designed an object for that: java.util.LinkedHashMap.
To set up your storage object use
java.util.Map<String, Integer> map = new java.util.LinkedHashMap<>()
Note the fancy diamond notation.
Then, with name as a string, write something like
if (map.containsKey(name)){
map.put(key, map.get(key) + 1);
} else {
map.put(key, 1);
}
This could be optimised a little: you could rely on the fact that map.get(key) will be null if key is not present. This obviates the need for the containsKey call.
Finally, to output your values use something on the lines of
for (java.util.Map.Entry<String, Integer> entry : map.entrySet()){
/*ToDo - use entry.getKey() and entry.getValue()*/
}
If you want your output to be sorted on the keys then use a java.util.TreeMap instead. If the order of output is of no consequence to you then use a java.util.HashMap.
I need to merge duplicates and add counter of duplicates.
When duplicate stuff comes to mind, think of Set to isolate. As and when you try to add an element to set and the add method returns false, print the data with 2 count.
But when the entries can occur more than twice, then you need to keep a track of each entry's count until the very end. So use a map instead with each String as key and its count as value. That basically means, while adding a string to map:
Get it from the map
- if not null, then get its value, increment 1 and set its value again.
- if null, then add it to map with value=1
At the end, you can iterate and find count.
I need to sort a hash map, first according to value then according to key.
TreeMap<String,Integer> dictionary = new TreeMap<String,Integer>();
For example, the desired output is something like:
it - 2
of - 2
the - 2
times - 2
was - 2
best - 1
worst - 1
I tried tree map, but that only sorts it according to key.
So basically, I need to sort my first according to the Integer (Highest to Lowest) and then according to the String (First A then B till Z).
I searched online and saw that I'm gonna have to use comparator but I'm not sure how to make it work?
Any guidance will be appreciated.
This is for a Java assignment.
The Map interface has no concept of "order", but you could sort the entries:
Map<String, Integer> map; // populated
List<Map.Entry<String, Integer>> entries = new ArrayList<> (map.entrySet());
Collections.sort(entries, new Comparator<Map.Entry<String, Integer>>() {
public int compareTo(Map.Entry<String, Integer> a, Map.Entry<String, Integer> b) {
return a.getValue().equals(b.getValue()) ? a.getKey().compareTo(b.getKey()) : Integer.compareTo(b.getValue(), a.getValue());
}
});
for (Map.Entry<String, Integer> entry : entries)
System.out.println(entry.getKey() + " - " + entry.getValue());
If java 8 is available, it becomes a lot neater:
Map<String, Integer> map; // populated
map.entrySet().stream()
.sorted( (a, b) -> a.getValue().equals(b.getValue()) ? a.getKey().compareTo(b.getKey()) : Integer.compareTo(b.getValue(), a.getValue()))
.map(e -> entry.getKey() + " - " + entry.getValue())
.forEach(System.out::println);
If absolutely need a map, load them into aLinkedHashMap, which "preserves order" in that it iterates over its entries in the same order they were inserted.
(I'm assuming this is something like Java). Sorted maps only deal with keys, not values. You probably want to just load the map content into a new TreeMap where each key is the original key and value combined somehow. Or, you can load into an List and sort that, or use a Set.
My map is declared as:
ListMultimap<String, String> myMutlimap = ArrayListMultimap.create();
I've been able to print just the keys:
TEN
TT2
TP1
TP2
TRK
TAL
COM
COM
COM
TCO
TPA
TYE
or the values or the keys and values:
TEN=children's story
TT2=black star
TP1=black star
TP2=5/13
TRK=This old album
COM=This album is good
COM=This album is great
COM=This album is awesome
TCO=hip-hop
TPA=1/2
TYE=2002
But, when I try to list the value of the "COM" key I get:
[This album is good, This album is great, This album is awesome ]
How can I get the individual values of the "COM" key without resorting to string splitting the "=" sign away? I think if I could get the key and value on the same line, it would also make it easy to assign them to variables.
TEN children's story
TT2 black star
TP1 black star
TP2 5/13
COM This album is good
COM This album is great
COM This album is awesome
or
COM This album is good
This album is great
This album is awesome
I know that are ways I can use these keys and values as variables already but, I am looking for a clean and succinct way to do this - that also prints nicely.
Edit:
As requested here are some methods I've tried:
for (Object key : myMutlimap.keys()) {
System.out.println(key);
}
for (Object value : myMutlimap.values()) {
System.out.println(value);
}
for (Object value : myMutlimap.entries()) {
System.out.println(value.toString());
}
for (String value : myMutlimap.keySet()) {
System.err.println(value);
System.out.println(myMutlimap.get("COM"));
}
Just use get() and iterate over the list that it returns to get the values individually.
List<String> values = myMutlimap.get("COM");
for (String s: values) {
System.out.println(s);
}
You're not using the type parameters of the Multimap (or even the return type of the methods, for that matter), so of course Object won't get you far.
With an instance of Multimap<String, String>, you have the following (interesting) methods available:
Map<String, Collection<String>> asMap() to get the Map view, where each key has a collection of values
Collection<Map.Entry<String, String>> entries() to get the individual entries, i.e. each (key, value) pair
Collection<String> get(String key) to get all the values for a given key
Multiset<String> keys() to get all the keys without duplicates and be able to know how many values are associated to each of them
Set<String> keySet() to get the Set of keys, again without duplicates
Collection<String> values() to get the collection of all values present in the Multimap, without knowing which key they are associated to
Knowing that, if you want to print the values for a given key, you just have to do this:
for (String value : myMultimap.get("COM")) {
System.out.println(value);
}
If you want to do the same for all available keys, you have several options:
Iterate on the keys and lookup their values:
for (String key : myMultimap.keySet()) {
for (String value : myMultimap.get(key)) {
System.out.println(key + " " + value);
}
}
Iterate on the entries of the Multimap (the (key, value) pairs):
for (Map.Entry<String, String> entry : myMultimap.entries()) {
String key = entry.getKey(), value = entry.getValue();
System.out.print(key + " " + value);
}
Iterate on the entries of the Map view:
for (Map.Entry<String, Collection<String>> entry :
myMultimap.asMap().entrySet()) {
String key = entry.getKey();
Collection<String> values = entry.getValue();
for (String value : values) {
System.out.println(key + " " + value);
}
}
This method has the advantage of giving you access to the collection of values for each key (so you have a nice collection with all its available methods, like size(), or that could can manipulate further), like in option 1, but without the need of an extra lookup in the Multimap for each key.