Map Entry conversion with Map Tree - java

So what I have been trying to do is use a TreeMap I previously had and apply it to this method in which I convert it into a set and have it go through a Map Entry Loop. What I wish to do is invert my previous TreeMap into the opposite (flipped) TreeMap
'When I run my code, it gives me a comparable error. Does this mean I have to implement the comparable method? I convereted the arrayList into an Integer so I thought the comparable method would support it. Or is it just something wrong with my code
Error: Exception in thread "main" java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.lang.Comparable
Overview: Originally, my intended purpose for the program was to make a Treemap that read from a text document and specifically found all the words and the index/rows of where the words were located. Now I wish to make a "top ten" list that contains the most used words. I wanted to "flip" my treemap so that the integer values would be what would be put in order and the string would follow
public static void getTopTenWords(TreeMap<String, ArrayList<Integer>> map) {
Set<Map.Entry<String, ArrayList<Integer>>> set = map.entrySet();
TreeMap<Integer, String> temp = new TreeMap<Integer, String>();
int count = 1;
for(Map.Entry<String, ArrayList<Integer>> entry : set){
if(temp.containsKey(entry.getValue())) {
Integer val = entry.getValue().get(count);
val++;
temp.put(val, entry.getKey());
}
else {
temp.put(entry.getValue().get(count), entry.getKey());
}
count++;
}
}

Now I wish to make a "top ten" list that contains the most used words.
I wanted to "flip" my treemap so that the integer values would be what
would be put in order and the string would follow
Note that a Map contains only unique keys. So, if you try to keep your count as key, then you would need to put it in your Map by creating a new object with new Integer(count).
If you put your count in Map like: - map.put(2, "someword"), then there are chances that your previous count value gets overwritten, because Integer caches the values in range: - [-128 to 127]. So, the integer values between these range will be interned if you don't create a new object. And hence two Integer with value say 2 will point to same Integer object, and hence resulting in duplicate key.
Secondly, in your code: -
if (temp.containsKey(entry.getValue()))
using the above if statement, you are comparing an ArrayList with an Integer value. temp contains key which are integers. And values in entry are ArrayList. So, that will fail at runtime. Also, since your orginal Map contains just the location of the word found in the text file. So, just what you need to do is, get the size of arraylist for each word, and make that a key.
You would need to modify your code a little bit.
public static void getTopTenWords(TreeMap<String, ArrayList<Integer>> map) {
Set<Map.Entry<String, ArrayList<Integer>>> set = map.entrySet();
TreeMap<Integer, String> temp = new TreeMap<Integer, String>();
for(Map.Entry<String, ArrayList<Integer>> entry : set) {
int size = entry.getValue().size();
int word = entry.getKey();
temp.put(new Integer(size), word));
}
}
So, you can see that, I just used the size of the values in your entry set. And put it as a key in your TreeMap. Also using new Integer(size) is very important. It ensures that every integer reference points to a new object. Thus no duplication.
Also, note that, your TreeMap sorts your Integer value in ascending order. Your most frequent words would be somewhere at the end.

Related

How can I iterate through a hashset within a hashmap?

I am trying to iterate through a hashmap which contains 8 entries. However one of these entries is a hashset 'balloon' with 2 objects within it. I want to add this to an array list so i can then iterate through it in a for loop/
First part of the code below works, I loop through the hashmap and look for the key I require which is 'balloon'. I need help to add the hashset to an array list.
I am getting a casting error when using Collectors.list and stream
//This is the hashmap I am looping through to find the balloon key
Map<String, Object> types = System.getPartyItems();
for (Map.Entry<String, Object> entry : types.entrySet()) {
if (StringUtils.contains(entry.getKey().toString(), "balloon")) {
//This is where I need to add the balloon hashset to a list to access the entries and values from within.
List<PartyItem> myPartyList = new ArrayList<>();
myPartyList.add (hash set of balloon objects)
Do i need to assign the hash set to a variable before i can set it to the list? Anything I've tried I am getting a casting error eg "class java.util.stream.ReferencePipeline$Head cannot be cast to class java.util.ArrayList"
Any help appreciated.
Thanks
Test if a value is a Set and if it is, add all items to your list.
if (StringUtils.contains(entry.getKey().toString(), "balloon")
&& entry.getValue() instanceof Set) {
myPartyList.addAll((Set)entry.getValue());
}
You can iterate like this:
for(String key: Map.keySet()){
if(StringUtils.contains(key, "balloon")){
Iterator<String> it = hashMap.get("balloon").iterator();
while(it.hasNext()){
// your code here
}
}
}
Instead of iterating through entry just iterate through keys and when you find the balloon get the hashset to iterate through it.
for(String key: types.keySet()){
if(StringUtils.contains(key, "balloon")){
for(Object object: types.get(key)){
//do what you need with object
}
}
}
After your edit it should be like this
for(String key: types.keySet()){
if(StringUtils.contains(key, "balloon")){
ArrayList<Set<PartyItem>> myList = new ArrayList();
myList.add(types.get(key));
}
}
Usually you structure your hashmap as <key, value> and you access your values via their corresponding keys. But they have to match exactly.
In your case your hashmap would look like this:
Map<String, Object> partyItems = myPartyList.getPartyItems();
// or maybe even
Map<String, PartyItem> partyItems = myPartyList.getPartyItems();
And getting the value is as easy as:
Object partyItem = partyItems.get("baloon");
If you are not sure if your paryItems contain a value for your key baloon you can check that first:
if (partyItems.contains("baloon")) {
Object partyItem = partyItems.get("baloon");
}
If you are looking for a part of the key matching baloon:
List<PartyItem> myFilteredPartyItems = partyItems.entrySet().stream()
.filter(e -> e.getKey().contains("baloon"))
.collect(Collectors.toList()))
This is called stream oriented programming (take a look at the Java Stream API), and if your run at least Java 8 you can use those.
And what it does, is turn the entries of the List to a stream, then remove everything which does not contain baloon in the key, and turn the resulting stream, which was not removed back to a list.
Here you also find a very informative tutorial on how to use streams in Java.

How to return keys of a map according to a condition?

I'm learning Java using BlueJ, I have made a class that has a HashMap of (Integer, String) that contains an ID number of somebody and their name.
I want a method to return a collection of all the keys that satisfy a condition, like if their ID number begins with 3 for example. I can't figure out how to do this.
And then another method that returns a collection of the values if they satisfy a condition, I was thinking it would be very similar to the previous method.
I know I need to loop through the map but I am not sure how to write the condition to populate the new map.
Here's an example that returns all the odd keys, in a Collection. Lists and Sets are Collections, in the same way that ArrayLists are Lists. You could change Collection to List (or even ArrayList) in this example and it would do the same thing.
public Collection<Integer> getOddKeys() {
// keySet is a method of Map that returns a Set containing all the keys (and no values).
Collection<Integer> result = new ArrayList<Integer>();
for(Integer key : map.keySet()) {
if((key % 2) == 0) // if the key is odd...
result.add(key); // ... then add it to the result
}
return result;
}
You should be able to modify this example to check the values instead - I won't just give you that code, because it's very similar, and easy to figure out if you understand how this example works.
You need to use the values method, which returns a collection of the values, in the same way that keySet returns a collection (more specifically, a set) of the keys. If you're wondering about why keySet returns a set and values doesn't, it's because you can use the same value twice in a map, but you can't use the same key twice.
You could do the following:
Create a holder list
Iterator over your map keys using map.keySet().iterator();
Check if the key start with 3, if yes add it to the key list.
return the keys list.
In your case (if the map is not too big), I'll get all keys of the map, then process them one by one to math my criteria:
Map<Integer, String> myMap=getFromSomeWhere();
for(Integer i : myMap.keySet() {
String k=String.valueOf(i);
if(k.startsWith("3")) {
//do what you want
}
}
public void CountryAbbriviationMap(String input)
{
map<string ,string> countrymap =new map<string ,string>{'Australia'=>'AUS','Argentina'=>'ARG', 'India'=>'IND'};
for(string key : countrymap.keySet())
{
if(key.startsWithIgnoreCase('A') && input.startsWithIgnoreCase('A'))
{
system.debug(key); //TO GET KEYS
system.debug(countrymap.get(key)); //TO GET VALUES
}
}
}

don't understand what is going on with hashmap when 2 objects have same hashcode

public class random {
public static class A{
int id= 1;
public int hashCode(){
return id;
}
}
public static void main(String[] args) {
Map<Integer, Integer> map= new HashMap<Integer, Integer>();
A a = new A();
A b = new A();
map.put(a.id, 1);
map.put(b.id, 2);
System.out.println(map.get(a.id));
System.out.println(map.get(b.id));
System.out.println(map.size());
}
}
output is
2
2
1
a and b have the same hashcode(bucket) and inside this bucket is (1 and 2). It says only one node exists which is b with the value of 2. When 2 hashcodes are the same do they override the current value? I read it is not the case.
from tutorial
*"Since hashcode is same, bucket location would be same and collision will occur in HashMap, Since HashMap use LinkedList to store object, this entry (object of Map.Entry comprise key and value ) will be stored in LinkedList.
Read more: http://javarevisited.blogspot.com/2011/02/how-hashmap-works-in-java.html#ixzz2sCM7fNED*
does this mean that my map now has 1 bucket with 2 values? how do I grab the value of (1)
You are using the Integer id as a key in the Map, not a or b. So the hashcode() of A is not used at all.
To get the values from a map, use the get method.
If you wanted to use a1 or a2 as the key, you would need to declare the map as such:
Map<A, Integer> map = new HashMap<>();
from the doc of hashmap of java (http://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html)
HashMap.put()
Associates the specified value with the specified key in this map. If
the map previously contained a mapping for the key, the old value is
replaced.
So the new value will replace the old value.
Both of them have the same id of "1", so when you add them to the map under the key of their id, they both get added with the key 1. So the second one overrides the first.
You've made a bit of a mess.
A Map maps between keys and values. In your example, you're mapping integers to integers. First you're trying to map 1 to 1, then 1 to 2. A map can only map a key once - if you map the key a second time, it overwrites the first mapping.
Hash collisions happen when two different keys have the same hash value. If you created a Map<A, Integer> and mapped A and B to to some values, you would have had a collision, but would have gotten a map with two elements.

Get key object out of a HashMap in Java

I would like to retrieve the original object of a key in a HashMap in Java, what is the best way to do it?
For example
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
Integer keyObj = new Integer(10);
Integer valueObj = new Integer(100);
// And add maybe 1 million other key value pairs here
//... later in the code, if I want to retrieve the valueObj, given the value of a key to be 10
Integer retrievedValueObj = map.get(10);
//is there a way to retrieve the original keyObj object with value 10 from map?
Basically, the user can query any value of key here just for the key object, 10 is just an example.
Some comment say, "you already have the x object, why do you want to get it?"
Well, this is the same as saying "you already have the value object, why do you want to get it?"
That is the purpose for the HashMap data structure, store and retrieval.
Retrieving a value object is easy but it seems no many people know how to retrieve the key object.
It seems like many people don't get why I want to achieve the object of 10 and ask why? why not just value 10. This is just a greatly simplified model.
Well, let me give a little bit context. The keyObj is data in another data structure and I need the exact reference of this original key object. Say, there is a linked list of all the key values, and if I want to remove a particular node in the linked list.
I am not only interested in the value "10", but also the memory location, i.e. the reference in Java of that "10" object. There could be many "10"'s in memory. But that exact object is what I want to retrieve.
The iterator approach answer below give an O(n) approach. But what I am looking for is an O(1) retrieval of the key OBJECT given the key value.
One way I can think of is to store the key object in value as well, like
class KeyAndValue {
public Integer key;
public Integer value;
public KeyAndValue(Integer key, Integer value) {
this.key = key;
this.value = value;
}
}
map<Integer, keyAndValueL> map = new map<Integer, keyAndValueL>();
Integer x = new Integer(10);
map.add(x, new KeyAndValue(x, 100));
//then I can retrieve the reference of x, given value of key 10
Integer newKeyObj = map.get(10).key;
but this approach uses more memory and looks like a hack to me. I am wondering if there is a more elegant way in Java.
A similar aproach but more generic is to store the "key + value" as an Entry instead of encapsule in another class.
Example:
Map<Integer, Entry<Integer, Integer>> map = new HashMap<Integer, Entry<Integer, Integer>>();
Integer x = new Integer(10);
map.put(x, new AbstractMap.SimpleEntry<Integer, Integer>(x, 100));
//then I can retrieve the reference of x, given value of key 10
Entry<Integer, Integer> keyObj = map.get(10);
try this
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
Integer keyObj = new Integer(10);
Integer valueObj = new Integer(100);
map.put(keyObj, valueObj);
Set<Integer> keys = map.keySet();
Iterator<Integer> iterator = keys.iterator();
while(iterator.hasNext()){
Integer x = iterator.next();
if(map.get(x) == 100)
System.out.println("key is "+ x);
}
You could store a key + value object "as the value" as you mention in your question.
What you are implementing is a variant of the flyweight pattern.
This is easiest implemented using a Map of every managed object to itself:
Map<T, T> cache = new HashMap<>();
And for every object you encounter:
T obj; // comes from somewhere
obj = cache.computeIfAbsent(obj, v -> obj); // reuse, or add to cache if not found
This has O(1) time complexity and uses only one extra object reference for each object so managed.

How do I sort elements in a hash table in alphabetical order?

How do I sort hash table elements alphabetically? For example, my elements are:
cijfercode, Zweeds, Doorloper, Kruizword, Crypto, Woordzoker
edit: I also got a solution for sorting the hashtable elements. Here is the solution:
java.util.Vector vec = new java.util.Vector(hashtableList.keySet());
Collections.sort(vec);
If these "elements" are keys you can store them in a TreeMap, which will produce a consistent order based on the natural ordering of the keys. Note you don't need to do much except create a new map with the old map passed to the constructor:
Map<String,?> map = ?
Map<String,?> orderedMap = new TreeMap<String,?>(map);
Then, iterate like normal:
for(String key : orderedMap.keys()){
}
If your "elements" are values, then you can insert them as keys into a TreeMap keeping track of the original keys, read the sorted order of values as before (basically creating an inverted index):
Map<?,String> map = ?
Map<String,List<?>> orderedVals = new TreeMap<String,List<?>>();
for(Entry<?,String> map : map.entrySet()){
List<?> keys = orderedVals.get(map.getValue());
if(keys == null){
keys = new ArrayList<?>();
orderedVals.put(map.getValue(), keys);
}
keys.add(map.getKey());
}
// now orderedVals has keys in sorted order
for(String val : orderedVals.keys()){
}
Of course, if you're not actually using anything related to the fact these things are in a "hashtable" (I read this as something implementing Map), then you can load up a List of your choosing, and sort it:
List<String> list = new ArrayList<String>(map.values()); // or use map.keys()
Collections.sort(list);
If you're not happy with the default sort order for String, feel free to write your own comparator:
Collections.sort(list, new Comparator<String>(){
public int compare(String left, String right){
return // your impl
}
});
compare must return a negative integer when the left comes first, 0 if left and right are the same, and a positive integer if right comes first.
Mark Elliot's idea is correct. I don't like the whole Map<?, List<?>> idea though; I've been far too spoilt on Guava. So here's a Guava version of the same idea:
SortedSetMultimap<String, ?> sorted = Multimaps.invertFrom(
Multimaps.forMap(map), TreeMultimap.create());
for (Map.Entry<String, ?> entry : sorted.entries()) {
// ...
}
This is, like, a third of the size of Mark's code. :-)
java.util.Vector vec =new java.util.Vector(hashtableList.keySet());
Collections.sort(vec);
Please check http://discuss.joelonsoftware.com/default.asp?joel.3.19588.13 for an interesting discussion on this.
Consider http://download.oracle.com/javase/1.4.2/docs/api/java/util/TreeMap.html too.

Categories