How to retrieve index of a map using key value?
I have a map with string as key and int as value.
I will pass map and key value to a method,in that method based on the index of the passed key value it will return either true or false. I need this util method for my application.
package sample;
import java.util.HashMap;
import java.util.Map;
public class MAp {
public static void main(String args[]) {
Map<String, Integer> sampleMap = new HashMap<String, Integer>();
sampleMap.put("ABC", 12);
sampleMap.put("DEF", 13);
boolean flag = canAllocate("ABC", sampleMap);
}
private static boolean canAllocate(String string, Map<String, Integer> sampleMap) {
if (sampleMap.containsKey("ABC")) {
int index = 0;
// I need to get index of "ABC" in map;
if (index == 0) {
return true;
}
}
return false;
}
}
I would suggest you try using a LinkedHashMap, which will preserve the order, then do as Mena suggested. Otherwise, the 'order' doesn't mean much.
You could just iterate the keySet and increment an int.
index i = 0;
for (String key: sampleMap.keySet()) {
if (key.equals(myString)) {
return i;
}
else {
i++;
}
}
return -1;
To be noted, there is no indexing as such in the key set, so the whole functionality seems to have little value.
" // I need to get index of "ABC" in map "
It has no sense to do that, "ABC" itself is a sort of index ine the MAP.
Key -> Map
Index -> Array/List
Related
Is there a code for finding a specific value in a hashmap?
I want to use a for loop to convert values in a hashmap into an int.
for (int i = 0; i < items; i++) {
cost = Integer.parseInt(myHashmap);
}
can I even use .parseInt on a hashmap or is there another way to convert a place in a hashmap into a int?
Like String[3] is there a code to find a specific place in a hashmap?
To iterate over all values of a map, use the values method:
Map<Long, String> map = ...;
for (final String value = map.values()) {
System.out.println(value);
}
To find a specific value, iterate all values, check against your predicate and return if found:
String findValue(final Map<Long, String> map, final Predicate<String> condition) {
for (final String value = map.values()) {
if (condition.test(value)) {
return value;
}
}
return null;
}
To find the key for a given value, iterate the entry set of the map:
Long findKey(final Map<Long, String> map, final String value) {
for (final Map.Entry<Long, String> entry = map.entrySet()) {
if (Objects.equals(entry.getValue(), value)) {
return entry.getKey();
}
}
return null;
}
Of course, once you have a value (or a key), you can use it any way you like. That includes passing it as argument to Integer.parseInt.
myHashmap.values() will return all the values of the Map. Integer.parseInt(value) parses the String argument as a signed decimal integer object.
public static void main(String[] args) {
Map<String, String> myHashmap = new HashMap<>();
myHashmap.put("A", "10");
myHashmap.put("B", "20");
myHashmap.put("C", "30");
myHashmap.values().forEach(value -> {
System.out.println(Integer.parseInt(value));
// Rest of the logic
});
}
In my WebApplication I have to check many incoming query parameters from the requestBody. In order not to write the same code in every method, I want to write a function that returns a boolean. When all required parameters are received and the values of the entrySet are not null the method should return true (otherwise false), i can use the incoming query parameters later on in the programm.
Therefore I pack all incoming parameters into a HashMap. Additionally I put a specific list into the method, which provides the required parameters(keys) for checking.
Example Map of queryParams:
Map queryParams = new HashMap();
queryParams.put("id", "1");
queryParams.put("name", "Jane");
queryParams.put("lastname", "Doe");
Example Array:
String[] keys = {"id", "name", "lastname"};
Last version of method:
public static Boolean checkRequestParams(Request request, String[] keys) {
Map params = (JsonUtil.fromJson(request.body(), HashMap.class));
Iterator it = params.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry) it.next();
for (int i = 0; i < keys.length; i++) {
if (pair.getKey().equals(keys[i])) {
return true;
}
}
The Array provides the keys which are the QueryParams the client sent. No i want to compare them and check if the keys in the Hashmap equals to the given keys in the array and if the values of the keys in the Map are not null.
I have tried many variations. Either I got nullPointerExceptions or I always got a null return.
I might be wrong, but as I understood you want to do validate the following condition:
The HashMap keys must belong to the following list of keywords {"id", "name", "lastname"}.
No value from the HashMap should be equal to null.
You might use something similar to this:
map.entrySet()
.stream()
.allMatch(entry -> keys.contains(entry.getKey()) && entry.getValue() != null)
So we iterate over the entrySet and check if entry key belong to the defined set and if value is not null.
Here is a more detailed example:
Set<String> keys = Set.of("id", "name", "lastname");
Map<String,List<Integer>> map = Map.of("id", List.of(1,2,3), "name", List.of(4,5,6));
map.entrySet()
.stream()
.allMatch(entry -> keys.contains(entry.getKey()) && entry.getValue() != null);
Map<String,List<Integer>> map1 = Map.of("id", List.of(1,2,3), "not in the keys", List.of(4,5,6));
map1.entrySet()
.stream()
.allMatch(entry -> keys.contains(entry.getKey()) && entry.getValue() != null);
Please note that I am using collections factory methods to create Map,List and Set which has been added to java-9, but stream api is available since java-8.
As for your code, you will always get true, because as soon as there is an entrySet which satisfies the condition the method will return result.
for (int i = 0; i < keys.length; i++) {
if (pair.getKey().equals(keys[i])) {
return true; // one single match found return true.
}
}
You can try to reverse the condition and return false as soon as there is a mismatch.
for (int i = 0; i < keys.length; i++) {
if (!pair.getKey().equals(keys[i]) || pair.getValue() == null) {
return false; // mismatch found, doesn't need to verify
// remaining pairs.
}
}
return true; // all pairs satisfy the condition.
I hope you find this useful.
Just using vanilla Java you could try something like this.
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ValidatorExample {
public boolean checkRequestParams(Map<String, Object> request, List<String> keys) {
return isEqualCollection(request.keySet(), keys)
&& !containsAnyNull(request.values());
}
private boolean isEqualCollection (Collection<?> a,Collection<?> b){
return a.size() == b.size()
&& a.containsAll(b)
&& b.containsAll(a);
}
private boolean containsAnyNull(Collection<?> collection){
return collection.contains(null);
}
public static void main(String[] args) {
ValidatorExample validatorExample = new ValidatorExample();
List<String> keys = Arrays.asList("id", "name", "lastname");
Map<String, Object> parametersOk = new HashMap<>();
parametersOk.put("id", "idValue");
parametersOk.put("name", "nameValue");
parametersOk.put("lastname", "lastnameValue");
// True expected
System.out.println(validatorExample.checkRequestParams(parametersOk, keys));
Map<String, Object> parametersWithInvalidKey = new HashMap<>();
parametersWithInvalidKey.put("id", "id");
parametersWithInvalidKey.put("name", "nameValue");
parametersWithInvalidKey.put("lastname", "lastnameValue");
parametersWithInvalidKey.put("invalidKey", "invalidKey");
// False expected
System.out.println(validatorExample.checkRequestParams(parametersWithInvalidKey, keys));
Map<String, Object> parametersWithNullValue = new HashMap<>();
parametersWithNullValue.put("id", null);
parametersWithNullValue.put("name", "nameValue");
parametersWithNullValue.put("lastname", "lastnameValue");
// False expected
System.out.println(validatorExample.checkRequestParams(parametersWithNullValue, keys));
}
}
But I would recommend you to use a validation framework if your project allows it for a more accurate validation.
Should not return immediately if a match is found as we want to test 'all required' parameters. Try something like:
String[] keys = {"id, "name", "lastname"};
public static Boolean checkRequestParams(Request request, String[] keys) {
Map params = (JsonUtil.fromJson(request.body(), HashMap.class));
for (int i = 0; i < keys.length; i++) {
Iterator it = params.entrySet().iterator();
boolean found = false;
while (it.hasNext()) {
Map.Entry pair = (Map.Entry) it.next();
if (pair.getKey().equals(keys[i])) {
found = true;
break;
}
}
if (!found) {
return false;
}
}
return true;
}
You are returning true on the first matching key, whereas you want to check whether all keys are present. Further, your code is incomplete, hence, it is impossible to give full diagnostics.
But anyway, there’s no sense in iterating over map here. Just use
public static Boolean checkRequestParams(Request request, String[] keys) {
Map<?,?> params = JsonUtil.fromJson(request.body(), HashMap.class);
for(String key: keys) {
if(params.get(key) == null) return false;
}
return true;
}
This will ensure that each key is present and not mapping to null (as “not mapping to null” already implies being present).
When not considering the possibility of an explicit mapping to null, you could check the presence of all keys as simple as
public static Boolean checkRequestParams(Request request, String[] keys) {
Map<?,?> params = JsonUtil.fromJson(request.body(), HashMap.class);
return params.keySet().containsAll(Arrays.asList(keys));
}
Alternatively, you could consider a map invalid if any mapped value is null, even if its key is not one of the mandatory keys. Then, it would be as simple as
public static Boolean checkRequestParams(Request request, String[] keys) {
Map<?,?> params = JsonUtil.fromJson(request.body(), HashMap.class);
return params.keySet().containsAll(Arrays.asList(keys))
&& !params.values().contains(null);
}
In this problem, I have to have a map with keys and values of strings to see if multiple keys map to the same value. In other words, my method should return true of no two keys map to the same value while false if it does. My attempt to approach this was to put all the maps into a collection and examine each elem to see if there are two copies of the same value; that doesn't seem to be working for me however. Any suggestions will be appreciated, thanks.
The prompt:
Write a method isUnique that accepts a Map from strings to strings as a parameter and returns true if no two keys map to the same value (and false if any two or more keys do map to the same value). For example, calling your method on the following map would return true:
{Marty=Stepp, Stuart=Reges, Jessica=Miller, Amanda=Camp, Hal=Perkins}
Calling it on the following map would return false, because of two mappings for Perkins and Reges:
{Kendrick=Perkins, Stuart=Reges, Jessica=Miller, Bruce=Reges, Hal=Perkins}
The empty map is considered to be unique, so your method should return true if passed an empty map.
My attempt:
public static boolean isUnique(Map<String, String> input) {
Collection<String> values = input.values(); // stores all the values into a collection
for (String names: values) { // goes through each string to see if any duplicates
Iterator<String> wordList = values.iterator(); // iterates words in values collection
int repeat = 0; // counts number of repeats
// goes through each elem to compare to names
if (wordList.hasNext()) {
if (wordList.next().equals(names)) {
repeat++;
}
}
if (repeat > 1) { // if more than one copy of the value exists = multiple keys to same value
return false; // If multiple copies of same value exists
}
}
return true; // all unique values
}
If I understand your question, then I would implement your method generically like so -
public static <K, V> boolean isUnique(Map<K, V> input) {
if (input == null || input.isEmpty()) {
return true;
}
Set<V> set = new HashSet<V>();
for (V value : input.values()) {
set.add(value);
}
return set.size() == input.size();
}
One solution can be during iterating through the Map, you can store the values in Set of Strings. So if the size of original Map and Set is same, then there is no value that maps to two or more Key of Map.
As far as implementation goes, it can be done as follows:
public boolean checkMap(Map<String, String> map) {
Set<String> set = new HashSet<String>();
for(Entry<String, String> entry:map.entrySet()) {
set.add(entry.getValue);
}
if(map.size == set.size)
return true;
return false;
}
The shortest way that I can think of to do this is
public static boolean valuesAreUnique(Map<K,V> input) {
Collection<V> values = input.values();
return (new HashSet<V>(values)).size() == values.size();
}
However, it's not the most performant way of doing this, because as it builds the set, it will keep adding elements even after a duplicate has been found. So it would most likely perform better if you do the following, which takes advantage of the return value from the add method of the Set interface.
public static boolean valuesAreUnique(Map<K,V> input) {
Set<V> target = new HashSet<V>();
for (V value: input.values()) {
boolean added = target.add(value);
if (! added) {
return false;
}
}
return true;
}
Shrikant Kakani's and Elliott Frisch's approach are correct. But, we can make it more efficient by stopping the iteration once we have found a duplicate:
public static boolean isUnique(Map<String, String> input) {
Set<String> uniqueValues = new HashSet<String>();
for (String value : input.values()) {
if (uniqueValues.contains(value)) {
return false;
}
uniqueValues.add(value);
}
return true;
}
The exercises from the book are specific to the chapter, and as far as I understand, it is expected to have a solution per the topic covered. Its understandable that there are multiple and better solutions, which have been submitted above, but the given exercise covers the Map, keys, values, and methods related to them. Using below method stops as soon as the Value is used the second time.
public static boolean isUnique(Map<String, String> map){
Map<String, Integer> check = new HashMap<String, Integer>();
for (String v : map.values()){
if (check.containsKey(v)){
return false;
} else {
check.put(v, 1);
}
}
return true;
}
This is not basically how to sort the HashMap based on keys. For that I could directly use TreeMap without a wink :)
What I have at the moment is
Map<String, Object> favoritesMap = new HashMap<String, Object>();
and its contents can be
["Wednesdays" : "abcd"]
["Mondays" : "1234"]
["Not Categorized" : "pqrs"]
["Tuesdays" : "5678"]
I want to sort the HashMap based on keys and additional to this I need "Not Categorized" to be the last one to retrieve.
So expected while iterating over keySet is
["Mondays", "Tuesdays", "Wednesdays", "Not Categorized"] i.e. sorted on keys and "Not Categorized" is the last one
Thought of going for HashMap while creating and at the end add ["Not Categorized" : "pqrs"] but HashMap does not guarantee the order :)
Any other pointers for the solution?
Are you specifically excluding TreeMap for some external reason? If not you could obviously use TreeMap with a specially made Comparator.
Have you considered any of the other SortedMaps?
If TreeMap is definitely out I would extend HashMap and make it look like there is always one more entry but that is certainly not a trivial piece of work. You should have a very good reason not to use a SortedMap before going down this road.
Added
Here is an example of how you can make a particular entry always sort to the end using a TreeMap:
// This key should always appear at the end of the list.
public static final String AtEnd = "Always at the end";
// A sample map.
SortedMap<String, String> myMap =
new TreeMap<>(
new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
return o1.equals(AtEnd) ? 1 : o2.equals(AtEnd) ? -1 : o1.compareTo(o2);
}
});
private void test() {
myMap.put("Monday", "abc");
myMap.put("Tuesday", "def");
myMap.put("Wednesday", "ghi");
myMap.put(AtEnd, "XYZ");
System.out.println("myMap: "+myMap);
// {Monday=abc, Tuesday=def, Wednesday=ghi, Always at the end=XYZ}
}
I wonder if you are looking for some variant of that?
You can achieve this by using LinkedHashMap as it guarantees to return results in the order of insertion.
Also check the following post to understand difference between map types.
Difference between HashMap, LinkedHashMap and TreeMap
Or just a create a custom class which holds a different key than the value. Sort according to the key of that class. For your case make the key same value as the day, and for "Not Categorized" case ensure that its key starts later than any of the other keys, for example make it "Z_Not Categorized".
public ComplexKey
{
String key;
String value;
}
ComplexKey monday = new ComplexKey("monday", "monday");
ComplexKey notCategorized = new ComplexKey("Z_Not Categorized", "Not Categorized");
Then you can write a custom comparator which sort the values according to the key of complexKey class.
In your case I would use a TreeMap:
Map<DayOfWeek, Object> favoritesMap = new TreeMap<>();
where DayOfWeek is a class you declare like:
class DayOfWeek implements Comparable<DayOfWeek> {
as it's not convenient to sort days of wooks as strings.
In fact, the keys are always sorted. If you output the map a couple of times, you will find that the result remains the same.
First I'll gossip again on hashing:
The reason is hashing. Each object has hashCode() method. The hash space is like a large array which contains all the possible hash values as indices. When a new element is inserted into a HashSet or a new pair is put into a HashMap, it is placed in the hash space according to its hash code. If two elements have the same hash code, they will be compared with equals() method, if unequal, then the new element will be placed next to it.
Then if you know what happens there, you can implement some code like below:
import java.util.*;
class MyString {
private String str;
public MyString (String str) {
this.str = str;
}
public String toString () {
return str;
}
public boolean equals (Object obj) {
if (obj.getClass().equals(MyString.class)) {
return obj.toString().equals(str);
}
return false;
}
public int hashCode () {
if (str.equalsIgnoreCase("Not Categorized")) {
return Integer.MAX_VALUE;
} else if (str.hashCode() == Integer.MAX_VALUE) {
return 0;
}
return str.hashCode();
}
}
public class Test {
public static void main (String args[]) {
Map<MyString, String> m = new HashMap<MyString, String>();
m.put(new MyString("a"), "a");
m.put(new MyString("c"), "c");
m.put(new MyString("Not Categorized"), "NC");
m.put(new MyString("b"), "b");
Set<MyString> keys = m.keySet();
for (MyString k : keys) {
System.out.println(m.get(k));
}
}
}
The result is "Not Categorized" always comes at last. The reason is simple: it's hash value is always the maximum of integer.
The reason I create a String wrapper class is String class is final, it can't be extended. So in this way, you would have your class structure a little change, but not much.
It is possible to use TreeMap, though it would be less efficient:
public static void main (String args[]) {
Map<String, String> m = new TreeMap<String, String>(new Comparator<String>() {
public int compare (String s1, String s2) {
if (s1.equals(s2)) {
return 0;
}
if (s1.equalsIgnoreCase("Not Categorized")) {
return 1;
}
if (s2.equalsIgnoreCase("Not Categorized")) {
return -1;
}
if (s1.hashCode() > s2.hashCode()) {
return 1;
} else if (s1.hashCode() < s2.hashCode()) {
return -1
} else {
return 0;
}
}
public boolean equals (Object obj) {
return false;
}
});
m.put("a", "a");
m.put("c", "c");
m.put("Not Categorized", "NC");
m.put("b", "b");
Set<String> keys = m.keySet();
for (String k : keys) {
System.out.println(m.get(k));
}
}
The result is the same. It will sort all the elements, but it won't change the hashing order of other strings, it only ensures "Not Categorized" always comes to be the largest one.
I want to retrieve the specific key associated with the value in a hashmap
I want to retrieve the key of "ME", how can I get it?
Code snippet :
HashMap<Integer,String> map = new HashMap<Integer,String>();
map.put(1,"I");
map.put(2,"ME");
There's a small problem with what you are trying to do. There can be multiple occurrences of the same value in a hashmap, so if you look up the key by value, there might be multiple results (multiple keys with the same value).
Nevertheless, if you are sure this won't occur, it can be done; see the following example:
import java.util.*;
public class Main {
public static void main(String[] args) {
HashMap<Integer, String> map = new HashMap<Integer, String>();
map.put(5, "vijf");
map.put(36, "zesendertig");
}
static Integer getKey(HashMap<Integer, String> map, String value) {
Integer key = null;
for(Map.Entry<Integer, String> entry : map.entrySet()) {
if((value == null && entry.getValue() == null) || (value != null && value.equals(entry.getValue()))) {
key = entry.getKey();
break;
}
}
return key;
}
}
Iterate over the entries of the map :
for(Entry<Integer, String> entry : map.entrySet()){
if("ME".equals(entry.getValue())){
Integer key = entry.getKey();
// do something with the key
}
}
You will have to iterate through the collection of keys to find your value.
Take a look at this post for details: Java Hashmap: How to get key from value?
If your values are guaranteed to be unique use Guava BiMap (the HashMap counterpart is called HashBiMap.
Integer key = map.inverse().get("ME");
Guava Documentation.
/**
* Return keys associated with the specified value
*/
public List<Integer> getKey(String value, Map<Integer, String> map) {
List<Integer> keys = new ArrayList<Integer>();
for(Entry<Integer, String> entry:map.entrySet()) {
if(value.equals(entry.getValue())) {
keys.add(entry.getKey());
}
}
return keys;
}