While writing test automation, i was required to leverage the api's provided by the developers and these api accepts HashMap as arguments. The test code involves calling several such api with hashmap as the parameter as shown below.
Map<String,String> testMap = new HashMap<String,String>();
setName()
{
testMap.put("firstName","James");
testMap.put("lastName","Bond");
String fullName=devApi1.submitMap(testMap);
testMap.put("realName",fullName);
}
setAddress()
{
testMap.put("city","London");
testMap.put("country","Britain");
testMap.put("studio","Hollywood");
testMap.put("firstName","");
testMap.put("person",myMap.get("realName"));
devApi2.submitMap(testMap);
}
However the requirement was to print the testMap in both setName and setAddress functions, but the map should print only those elements (key-value pairs) in alternate lines which are set in the respective function. I mean setName should print 2 elements in the Map which are set before submitMap api is invoked and similarly setAddress should print 5 elements which are set before submitMap is invoked.
setName Output must be:
The data used for firstName is James.
The data used for lastName is Bond
setAddress Output must be:
The data used for city is London.
The data used for country is Britain.
The data used for studio is Hollywood.
The data used for firstName is null.
The data used for person is James Bond
Any help, in order to acheive this?
I would probably write a helper function that would add items to the map and do the printing.
public static <K,V> void add(Map<K,V> map, K key, V value){
System.out.println(String.format("The data used for \"%s\" is \"%s\"", key, value));
map.put(key, value);
}
If you need to print different messages you could either use different helper functions or pass format string as an argument.
I would create a method which takes a comma separated list of keys as argument and print only them.
Something like:
public void printKeys(Map<String,String> map, String csKeys) {
for(String key: csKeys.split(",")){
if(map.conatinsKey(key)){
System.out.println("The data used for " + key + " is " + map.get(key) );
}
}
}
and you can invoke it like:
printKeys(testMap, "firstName,lastName");
printKeys(testMap, "city,country,studio");
You'd better create a copy of your testMap when you invoke the submitMap method, since you don't have a flag to indicate which key-value pairs should be printed.
You could do it like
Map<String, String> printObj = new HashMap<String, String>
setName()
{
testMap.put("firstName","James");
testMap.put("lastName","Bond");
String fullName=devApi1.submitMap(testMap);
printObj.addAll(testMap);
testMap.put("realName",fullName);
}
Then print the printObj instead of testMap.
From you comments on my earlier answer it seems you don't want the values put from one method to be displayed in the second one...
That can be done easily, just place:
testMap.clear();
in the beginning of every method.
Related
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 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>();
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 have a hashmap as follows
Map <String, List<String>> map = new HashMap <String, List<String>>();
After I did a map.put(), my map looks something like this:
Key - key1
Values - [value1]
Key - key2
Values - [value1, value2, value3]
Now I am reading a line from a file. File is like this:
Key:key2, Value:value1
I am storing the key1 and value1 in 2 elements called keyRead and valueRead. Inside the line reader, if I am using containsKey() and containsValue(), it is not working.
if(map.containsKey(keyRead){
S.O.P("Inside key match");
if(map.containsValue(valueRead){
S.O.P ("Inside value match");
}
}
The output is showing the inside key match but it is not showing the inside value match.
Can someone please tell me what I am missing here?
You need to do something like
if(map.containsKey(keyRead)) {
if(map.get(keyRead).contains(valueRead)) {
System.out.println("Inside value match");
}
}
Your values are lists, not strings. If you need to check if the string is contained by the list, you need to get the list first, then invoke the contains method of that list, passing the string as argument.
i think you have to loop through the values in the list like this, btw i have not tested the code -
if(map.containsKey(keyRead){
S.O.P("Inside key match");
forEach(List l: map.get(keyRead)) {
forEach(String s : l) {
if(s.equals(valueRead)) {
S.O.P ("Inside value match");
}
}
}
}
As has been pointed out, you cannot do a containsValue using an instance where the value is a List. Try using Guava's Multimap. This implements a Map where a key maps to multiple values.
Multimap has a containsEntry(key, value) that works exactly as you desire in that it matches the key and that the list associated with the key contains the value.
I have a Hashmap which may contain wildcards (*) in the String.
For instance,
HashMap<String, Student> students_;
can have John* as one key. I want to know if JohnSmith matches any elements in students_. There could be several matches for my string (John*, Jo*Smith, etc). Is there any way I can get a list of these matches from my HashMap?
Is there another object I could be using that does not require me to iterate through every element in my collection, or do I have to suck it up and use a List object?
FYI, my collection will have less than 200 elements in it, and ultimately I will want to find the pair that matches with the least amount of wildcards.
It's not possible to achieve with a hasmap, because of the hashing function. It would have to assign the hash of "John*" and the hash of "John Smith" et al. the same value.
You could make it with a TreeMap, if you write your own custom class WildcardString wrapping String, and implement compareTo in such a way that "John*".compareTo("John Smith") returns 0. You could do this with regular expressions like other answers have already pointed out.
Seeing that you want the list of widlcard matchings you could always remove entries as you find them, and iterate TreeMap.get()'s. Remember to put the keys back once finished with a name.
This is just a possible way to achieve it. With less than 200 elements you'll be fine iterating.
UPDATE: To impose order correctly on the TreeSet, you could differentiate the case of comparing two WildcardStrings (meaning it's a comparation between keys) and comparing a WildcardString to a String (comparing a key with a search value).
You can use regex to match, but you must first turn "John*" into the regex equivalent "John.*", although you can do that on-the-fly.
Here's some code that will work:
String name = "John Smith"; // For example
Map<String, Student> students_ = new HashMap<String, Sandbox.Student>();
for (Map.Entry<String, Student> entry : students_.entrySet()) {
// If the entry key is "John*", this code will match if name = "John Smith"
if (name.matches("^.*" + entry.getKey().replace("*", ".*") + ".*$")) {
// do something with the matching map entry
System.out.println("Student " + entry.getValue() + " matched " + entry.getKey());
}
}
You can just iterate your Map without converting it into a list, and use the String matches function, wih uses a regexp.
If you want to avoid the loop, you can use guava like this
#Test
public void hashsetContainsWithWildcards() throws Exception {
Set<String> students = new HashSet<String>();
students.add("John*");
students.add("Jo*Smith");
students.add("Bill");
Set<String> filteredStudents = Sets.filter(students, new Predicate<String>() {
public boolean apply(String string) {
return "JohnSmith".matches(string.replace("*", ".*"));
}
});
assertEquals(2, filteredStudents.size());
assertTrue(filteredStudents.contains("John*"));
assertTrue(filteredStudents.contains("Jo*Smith"));
}