I am using processing, and I have a HashMap, in which I want to be able to increment all the values by 1.
The code looks like this:
HashMap<Character, Integer> keyStates = new HashMap<Character, Integer>();
void press(Character k) {
keyStates.put(k, 1);
}
void release(Character k) {
keyStates.put(k, 0);
}
And the Integer tells me how long I have been pressing a key. Thus, I want to increment all the values of this HashMap by one, regardless of key, every "tick" or frame. Is there a way to increment all Integer Values of a HashMap, or, if not, another way of getting around this issue. Thank you very much for your help. Also, this is my first post, so please tell me if I am doing it right.
The best way to do it would be by using Iterator :
Iterator<Map.Entry <Character, Integer> > it = keyStates.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Character, Integer> pair = it.next();
Integer newCount = (pair.getValue() == null) ? 1 : pair.getValue() + 1 ;
pair.setValue(newCount);
}
Related
So I have this hashmap named "hm" which produces the following output(NOTE:
this is just a selection) :
{1=35, 2=52, 3=61, 4=68, 5=68, 6=70, 7=70, 8=70, 9=70, 10=72, 11=72}
{1=35, 2=52, 3=61, 4=68, 5=70, 6=70, 7=70, 8=68, 9=72, 10=72, 11=72}
{1=35, 2=52, 3=61, 4=68, 5=68, 6=70, 7=70, 8=70, 9=72, 10=72, 11=72}
This output was created with the following code(NOTE : the rest of the class code is not shown here) :
private int scores;
HashMap<Integer,Integer> hm = new HashMap<>();
for (int i = 0; i < fileLines.length(); i++) {
char character = fileLines.charAt(i);
this.scores = character;
int position = i +1;
hm.put(position,this.scores);
}
System.out.println(hm);
What I am trying to do is put all these hashmaps together into one hashmap with as value the sum of the values per key. I am familiar with Python's defaultdict, but could not find an equivalent working example. I have searched for an answer and hit those answers below but they do not solve my problem.
How to calculate a value for each key of a HashMap?
what java collection that provides multiple values for the same key
is there a Java equivalent of Python's defaultdict?
The desired output would be :
{1=105, 2=156, 3=183 , 4=204 ,5=206 ..... and so on}
Eventually the average per position(key) has to be calculated but that is a problem I think I can fix on my own when I know how to do the above.
EDIT : The real output is much much bigger ! Think about 100+ of the hashmaps with more than 100 keys.
Try with something like that
public Map<Integer, Integer> combine(List<Map<Integer, Integer>> maps) {
Map<Integer, Integer> result = new HashMap<Integer, Integer>();
for (Map<Integer, Integer> map : maps) {
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
int newValue = entry.getValue();
Integer existingValue = result.get(entry.getKey());
if (existingValue != null) {
newValue = newValue + existingValue;
}
result.put(entry.getKey(), newValue);
}
}
return result;
}
Basically:
Create a new map for the result
Iterate over each map
Take each element and if already present in the result increment the value, if not put it in the map
return the result
newHashMap.put(key1,map1.get(key1)+map2.get(key1)+map3.get(key1));
i have this kind of data structure
Map<Integer, Integer> groupMap= new LinkedHashMap<>();
groupMap.put(10, 1);
groupMap.put(11, 0);
groupMap.put(14, 1);
groupMap.put(13, 0);
groupMap.put(12, 0);
groupMap.put(15, 1);
what can be the best way to find the key which has value 1 if i have a present key with one value.
Ex:i have key 14, now need to find the key 15 which has value 1
least looping will be helpfull.
my approch:
List<Integer> keys = new ArrayList<>();
keys.putAll(groupMap.keySet());
//getting the index of current key i have
int index = keys.indexOf(14);
if(keys.size() == index) return -1;
for(int i = index+1;i<keys.size();i++){
if(groupMap.get(i) == 1) return i;
}
i know it isn't a very good approach, but can you please suggest a good one.
This completely defeats the purpose of a key-value map. But if it's really what you want, I suppose you could do the following:
public static int getNextKeyByValue(int value, int previousKey) {
final Map<Integer, Integer> groupMap = new HashMap<>();
Iterator iterator = groupMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<Integer, Integer> entry = (Map.Entry<Integer, Integer>) iterator.next();
if (entry.getValue() == value && entry.getKey() != previousKey) {
return entry.getKey();
}
}
return -1;
}
From the topic which #Titus mentioned in the comment, the most elegant and shortest solution is to use stream:
int getFirstCorrectValueBiggerThan (int lastValue) {
return groupMap.entrySet().stream()
.filter(entry -> Objects.equals(entry.getValue(), 1))
.map(Map.Entry::getKey)
.filter(value -> value > lastValue)
.findFirst();
}
edit:
sorry for the mistake, the code provided does not solve your problem since it is comparing keys not indexes. Here you have proper version, however it is not so cool anymore.
ArrayList<Integer> filteredList = groupMap.entrySet().stream()
.filter(entry -> entry.getValue().equals(1))
.map(Map.Entry::getKey)
.collect(Collectors.toCollection(ArrayList::new));
int nextCorrectElement = filteredList.get(filteredList.indexOf(14) + 1);
update
as far as i undestand what is written in this tutorial about map:
When a user calls put(K key, V value) or get(Object key), the function computes the index of the bucket in which the Entry should be. Then, the function iterates through the list to look for the Entry that has the same key (using the equals() function of the key).
and check out this topic about hash map complexity.
O(1) certainly isn't guaranteed - but it's usually what you should assume when considering which algorithms and data structures to use.
On top of that, the key part of your solution- the ArrayList::indexOf- is O(N) complex- you have to iterate through each element till the one which meets the condition. More info is in this topic.
So efectively you are iterating through every element of your hashmap anyway. And what is more, the hashmap searching (get method) is not quaranteed to be O(1) complex so there is a chance that you will double your work.
I have made a simple test of performance for stream based solution and simple loop proposed in this topic. In fact loop will be faster than sequential stream for each case I think, but still if you want that kind of performance gain then try to write it in in C++. Otherwise if you have more complex example then using the parallel stream may get some advantage due to higher abstraction level of the problem stating.
I have not really clear your question. If you are looking for all the tuples with value equals to 1, you could follow the approach below:
for (Entry<Integer, Integer> entry : groupMap.entrySet()) {
if (entry.getValue() == 1) {
System.out.println("The key is: " + entry.getKey().toString());
}
}
I'm writing a project that captures Java keywords from a .java file and keeps track of the occurrences with a map. I've used a similar method in the past successfully, but I can't seem to adopt this method for my intended use here.
Map<String,Integer> map = new TreeMap<String,Integer>();
Set<String> keywordSet = new HashSet<String>(Arrays.asList(keywords));
Scanner input = new Scanner(file);
int counter = 0;
while (input.hasNext())
{
String key = input.next();
if (key.length() > 0)
{
if (keywordSet.contains(key))
{
map.put(key, 1);
counter++;
}
if(map.containsKey(key)) <--tried inner loop here, failed
{
int value = map.get(key);
value++;
map.put(key, value);
}
}
This block of code is supposed to add the keyword to the key, and increment the value each time the same key occurs. So far, it adds the keywords, but fails to properly increment the value. here is a sample output:
{assert=2, class=2, continue=2, default=2, else=2, ...}
Basically it increments every value in the map instead of the ones it's supposed to. I'm not sure if I'm over-thinking this or what. I've tried an inner loop and it gave me insane results. I really hope I'm just over-thinking this. Any help is greatly appreciated!
There's a much more concise (and easier to reason about) way to achieve what you want:
final ConcurrentMap<String, AtomicInteger> map = new ConcurrentHashMap<>();
final Scanner input = new Scanner(file);
while (input.hasNext()) {
final String key = input.next();
if (key.length() > 0) {
map.putIfAbsent(key, new AtomicInteger(0));
map.get(key).incrementAndGet();
}
}
Let's analyze why does this work.
Whenever the Scanner encounters a keyword, there are 2 possible cases: you either have encountered it before (ie, it is a known keyword), or it is an yet unseen keyword.
If it is an unseen keyword: putIfAbsent will put an AtomicInteger with value 0 in the map, and incrementAndGet() will set it to 1 right after, and, from now on, it becomes a known keyword;
If it is a known keyword: putIfAbsent will do nothing, and incrementAndGet() will increment the value that is already present in the map.
Then, if you want the key set, you do:
final Set<String> keys = map.keySet();
To print all the values, you could do something like:
for (final String k : map.keySet()) {
System.out.println(k + ": " + map.get(k).get());
}
You are not forced to use the two "different" classes I used above, ConcurrentMap and AtomicInteger. It is just easier to use them because they encapsulate much of the logic that you tried to write by yourself (and failed). The logic that they encapsulate is exactly all the other answers describe (ie, test if the value is present, if not set it to 0, then get whatever value is present, increment it and put it back into the map).
To maintain the keys of the map (our words being counted) in alphabetical order, use a ConcurrentNavigableMap such as ConcurrentSkipListMap .
For every key you scan you create a new entry in the map (overriding the existing one). Then, the next condition holds so you increment the count by 1, reaching the value 2.
The inner part should be something like:
if (keywordSet.contains(key))
{
Integer value = map.get(key);
if (value == null)
value = 0;
value++;
map.put(key, value);
}
Anyway, consider using some kind of a mutable integer to make this more efficient. You won't have to override entries in the map, and you won't be doing too much Integer boxing operations.
Even more concise using Map.merge (since Java 8):
if (keywordSet.contains(key)) {
map.merge(key, 1, (currentCount, notUsed) -> ++currentCount);
}
Here is a generic implementation of a counting map - a map with values representing the count of their keys:
public static <K> void count(K key, Map<K, Integer> map) {
map.merge(key, 1, (currentCount, notUsed) -> ++currentCount);
}
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
count("A", map);
count("B", map);
count("A", map);
count("Z", map);
count("A", map);
System.out.println(map); // {A=3, B=1, Z=1}
}
You always set the value to 1 and then update it by another one. What you need is to update the map value (and not setting it to 1 again).
Instead of:
map.put(key, 1);
use:
Integer value = map.get(key);
if (value == null){
value = 0
}
value++;
map.put(key, value);
And drop the second if.
Map<String, Integer> map = new HashMap<String, Integer>();
Set<String> keywordSet = new HashSet<String>(Arrays.asList(keywords));
Scanner input = new Scanner(file);
while (input.hasNext()){
String key = input.next();
if (key.length() > 0)
if (keywordSet.contains(key)){
Integer counter = map.get(key);
if (counter == null)
map.put(key, 1);
else
map.put(key, count + 1);
}
}
map.compute(key, (k, value) -> (value == null) ? 1 : (value + 1));
I am currently using 2 for loops to compare all entries but I am getting duplicate comparisons. Because HashMaps aren't ordered, I can't figure out how to eliminate comparisons that have already been made. For example, I have something like:
for(Entry<String, String> e1: map.entrySet())
{
for(Entry<String, String> e2: map.entrySet())
{
if (e1.getKey() != e2.getKey())
{
//compare e1.getValue() to e2.getValue()
}
}
}
The problem with this is that the first entry will be compared to the second entry and then the third entry and so on. But then the second entry will again be compared to the first entry and so on. And then the third entry will be compared to the first entry, then the second entry, then the 4th entry, etc. Is there a better way to iterate through HashMaps to avoid doing duplicate comparisons?
Additional information:
To be more specific and hopefully answer your questions, the HashMap I have is storing file names (the keys) and file contents (the values) - just text files. The HashMap has been populated by traversing a directory that contains the files I will want to compare. Then what I am doing is running pairs of files through some algorithms to determine the similarity between each pair of files. I do not need to compare file 1 to file 2, and then file 2 to file 1 again, as I only need the 2 files to be compared once. But I do need every file to be compared to every other file once. I am brand new to working with HashMaps. agim’s answer below might just work for my purposes. But I will also try to wrap my brain around both Evgeniy Dorofeev and Peter Lawrey's solutions below. I hope this helps to explain things better.
If you are not careful, the cost of eliminating duplicates could higher than the cost of redundant comparisons for the keys at least.
You can order the keys using System.identityHashCode(x)
for(Map.Entry<Key, Value> entry1: map.entrySet()) {
Key key1 = entry1.getKey();
int hash1 = System.identityHashCode(key1);
Value value1 = entry1.getValue();
for(Map.Entry<Key, Value> entry2: map.entrySet()) {
Key key2 = entry2.getKey();
if (key1 > System.identityHashCode(key2)) continue;
Value value2 = entry1.getValue();
// compare value1 and value2;
}
}
How about this solution:
String[] values = map.values().toArray(new String[map.size()]);
for (int i = 0; i < values.length; i++) {
for (int j = i+1; j<values.length; j++) {
if (values[i].equals(values[j])) {
// ...
}
}
}
Try
HashMap<Object, Object> map = new HashMap<>();
Iterator<Entry<Object, Object>> i = map.entrySet().iterator();
while (i.hasNext()) {
Entry next = i.next();
i.remove();
for (Entry e : map.entrySet()) {
e.equals(next);
}
}
Note that there is no sense comparing keys in a HashMap they are always not equal. That is we could iterate / compare values only
If I understand correctly, you just want to know if there are any duplicates in the map's values? If so:
Set<String> values = new HashSet<String>(map.values());
boolean hasDuplicates = values.size() != map.size();
This could be made more efficient if you kick out once you find the first duplicate:
Set<String> values = new HashSet<String>();
for (String value : map.values()) {
if (!values.add(value)) {
return true;
}
}
return false;
public static boolean compareStringHashMaps(Map<String, String> expectedMap, Map<String, String> actualMap) throws Exception
{
logger.info("## CommonFunctions | compareStringHashMaps() ## ");
Iterator iteratorExpectedMap = expectedMap.entrySet().iterator();
Iterator iteratorActualMap = actualMap.entrySet().iterator();
boolean flag = true;
while (iteratorExpectedMap.hasNext() && iteratorActualMap.hasNext()){
Map.Entry expectedMapEntry = (Map.Entry) iteratorExpectedMap.next();
Map.Entry actualMapEntry = (Map.Entry) iteratorActualMap.next();
if(!expectedMapEntry.getKey().toString().trim().equals(actualMapEntry.getKey().toString().trim()))
{
flag = false;
break;
}
else if (!expectedMapEntry.getValue().toString().trim().equals(actualMapEntry.getValue().toString().trim()))
{
flag = false;
break;
}
}
return flag;
}
Considering the entries of a HashMap is Integer.
This returns the maximum entry within a HashMap.
int maxNum = 0;
for (Object a: hashMap.keySet()) {
if ((int)hashMap.get(a) > maxNum) {
maxNum = (int)hashMap.get(a);
}
}
You could try using a 2D array of results. If the result is already populated, then don't perform the comparison again. This also has the benefit of storing the results for later use.
So for an int result you would be looking at something like this: Integer[][] results = new Integer[map.entrySet().size()][map.entrySet().size()];This initialises the array to nulls and allows you to check for existing results before comparison. One important thing to note here is that each comparison result should be stored in the array twice, with the exception of comparisons to itself. e.g. comparison between index 1 and index 2 should be stored in results[1][2] and result[2][1].
Hope this helps.
I am working on a simple project that obtains data from an input file, gets what it needs and prints it to a file. I am basically getting word frequency so each key is a string and the value is its frequency in the document. The problem however, is that I need to print out these values to a file in descending order of frequency. After making my hashmap, this is the part of my program that sorts it and writes it to a file.
//Hashmap I create
Map<String, Integer> map = new ConcurrentHashMap<String, Integer>();
int valueMax = -1;
//function to sort hashmap
while (map.isEmpty() == false){
for (Entry<String, Integer> entry: map.entrySet()){
if (entry.getValue() > valueMax){
max = entry.getKey();
System.out.println("max: " + max);
valueMax = entry.getValue();
System.out.println("value: " + valueMax);
}
}
map.remove(max);
out.write(max + "\t" + valueMax + "\n");
System.out.println(max + "\t" + valueMax);
}
When I run this i get:
t 9
t 9
t 9
t 9
t 9
....
so it appears the remove function is not working as it keeps getting the same value. I'm thinking i have an issue with a scope rule or I just don't understand hashmaps very well.
If anyone knows of a better way to sort a hashmap and print it, I would welcome a suggestion.
thanks
Your code doesn't work because on every subsequent iteration, entry.getValue() > valueMax is never true because you don't reset valueMax on re-entry into the while loop.
You don't need to muck around with double-looping over a concurrently accessible map though.
ConcurrentSkipListMap has a lastKey method that returns the greatest key and doesn't require iteration over the entire map.
From your code it looks like you aren't resetting valueMax at the end of your loop. This means the first time round the loop you'll find the maximum but you'll never find any subsequent values because you'll still be comparing to the overall maximum.
Hashmap: no order. You can use ArrayList, which implements List to have an order.
Take a look : http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html
I guess it's because there no entries in map with key > initial value of valueMax, so condition if (entry.getValue() > valueMax) never true.
Additionally, there's TreeMap which holds it's contents sorted, so you can just iterate over it's entrySet() w/o any additional logic.
What about something like (not tested)
final Map<String, Integer> map = new ConcurrentHashMap<String, Integer>();
final Comparator <String, String> comparator = new Comparator ()
{
compare(String o1, String o2)
{
return map.get(o1) - map.get(o2);
}
};
final TreeMap <String, Integer> sortedMap = new TreeMap (comparator);
sortedMap.addAll(map);
System.out.println(sortedMap);