Find element in Java HashMap<String, String[]> - java

I'm having trouble to find an element inside my String array contained inside my HashMap. I have a String that is indeed inside this String[] but doing the following does not work.
if (groupOuMap.containsValue("someString")) {
groupOu = "someString";
}
My goal is to find the corresponding key of my HashMap where the value is found.
Exemple with a sample of my map :
nedcard.nl -> ["Wijchen account"]
mic.ad -> ["Ayutthaya4", "Brazil", "Changi", "Dresden", "Guangzhou"]
If I search for the String Brazil, I'd like to have a new Array of String which would be :
String[] groupOu = {"mic.ad", "Brazil"};
I have tried to used groupOuMap.values().contains() as well with no success.
Am I doing this wrong? Thank you!

In Java the easiest way to do this is probably just to iterate through each key-value pair in the map, and search for the first occurrence of the search term in the array that is the value. When found, return both the key and the value. If not found, return null.
public static String[] keyContainingValue(HashMap<String, String[]> map, String searchFor) {
for (String key : map.keySet()) {
String[] values = map.get(key);
// construct for replicating List.contains() on a primitive array
if (Arrays.stream(values).anyMatch(i -> i.equals(searchFor))) {
return {key, searchFor};
}
}
return null;
}

You can filter over the entrySet via Streams.
public static String[] search(Map<String, String[]> map, String value){
return map.entrySet().stream()
.filter(e -> Arrays.stream(e.getValue()).anyMatch(value::equals))
.findAny().map(e -> new String[]{e.getKey(), value}).orElse(null);
}
//...
Map<String, String[]> map = Map.of("mic.ad", new String[]{"Ayutthaya4", "Brazil", "Changi", "Dresden", "Guangzhou"}, "nedcard.nl", new String[]{"Wijchen account"});
System.out.println(Arrays.toString(search(map, "Brazil"))); // [mic.ad, Brazil]
Demo

Related

How do I build up in a map with one Key with many Values in Java 7

I want to build up a map based on 2 arrays where 1 key has many objects inside it.
Key: "Letter A" Value: "Albatross"
Value: "Alligator"
Key: "Letter B" Value: "Badger"
Value: "Bandicoot"
The structure must show the key 1 time, without repetitions
Hope the code is self explanatory.
Java 7:
public Map<String, List<String>> group(String[] input) {
Map<String, List<String>> result = new HashMap<>();
for (String str : input) {
String key = "Letter " + str.charAt(0);
if (result.containsKey(key)) {
result.get(key).add(str);//if Key already exists, just add this word to existing list.
} else {
List<String> list = new ArrayList<>();
list.add(str);
result.put(key, list); //Otherwise, create a new list and add the new word into the list
}
}
return result;
}
Java 8:
public static Map<String, List<String>> group(String[] input) {
return Arrays.stream(input)
.collect(Collectors.groupingBy(k -> "Letter " + k.charAt(0)));
//Provide the key for how you want to group. In your case it is first character of string.
}
You can use Guava's Mutlimap implementation, however that may not be Java 7 compatible. https://guava.dev/releases/23.0/api/docs/com/google/common/collect/Multimap.html
You can get the same effect by using a List for the values in your map like so:
Map<String, List<String>> map = new HashMap<>();
Then, let's say for each entry you want to add to the map you have the key in key and value in val, add it like so:
List<String> list = map.get(key);
if (list == null) {
list = new ArrayList<>();
map.put(key, list);
}
list.add(val);

Java HashMap key fits to a pattern?

I have a Map dataset, and I want to iterate through the keys and search for matches.
So I want to find the maps element, where the key fits to this pattern:
String searchedKey = "A?C"; // ? means it can be any character
Map<String, MyObject> myMap = new HashMap<>();
myMap.put("ABC", MyObject(1));
myMap.put("CDF", MyObject(2));
myMap.put("ADS", MyObject(3));
for (Map.Entry<String,MyObject> entry : myMap.entrySet()) {
// in this case, I want to find the first element, because it's key fits the searchedKey, where ? can be anything
}
How can I do this?
Thanks!
You could do something like this to return a list of found MyObjects. Note I changed ? to . for any character.
String searchedKey = "A.C"; // ? means it can be any character
Map<String, MyObject> myMap = new HashMap<>();
myMap.put("ABC", new MyObject(1));
myMap.put("CDF", new MyObject(2));
myMap.put("ARS", new MyObject(3));
myMap.put("VS", new MyObject(4));
myMap.put("AQC", new MyObject(3));
myMap.put("DS", new MyObject(3));
myMap.put("ASC", new MyObject(10));
List<Map.Entry<String,MyObject>> list = myMap.entrySet().stream()
.filter(e -> e.getKey().matches(searchedKey))
.collect(Collectors.toList());
list.forEach(System.out::println);
Prints
ASC=10
ABC=1
AQC=3
The MyObject class
class MyObject {
int val;
public MyObject(int v) {
this.val = v;
}
public String toString() {
return val + "";
}
}
You could use Regex-Patterns that allow to search Strings for matchings of a logical sequence using String#matches(String).
Here is a page that might help you create and test a regex for your needs. You might also have to construct your pattern flexible during runtime, depending on how your search works.
Tho keep in mind that a HashMap does not keep the order in which the keys were inserted. keySet() does not return them in a fixed order. If you need them ordered, you could use a LinkedHashMap

How to put together multiple Maps <Character, Set<String>> without overriding Sets

In my project I am using two maps Map<Character, Set<String>>.
map1 - is temporally holding needed values
map2 - is summing all data from map1 after each loop
for example i got:
map2 = (B; Beryllium, Boron, Bromine)
map2 = (H; Hellum, Hydrogen, Hafnium)
now new map1 is:
map1 = (B; Bismuth)
map1 = (O; Oxygen)
In my code adding Oxygen as new entry is ok, but adding new entry for B ends by overraidding existing data in values and leave me only Bismuth.
My code:
while (iterator.hasNext()) {
Set<String> words = new TreeSet<>();
String word = iterator.next();
char[] wordChars = word.toCharArray();
//some code
words.add(word);
map1.put(wordChars[i], words);
}
map2.putAll(map1);
I tought about using .merge but I have no idea how to use it with Sets as values, and I cannot use simple Strings with concat.
You can use Map#merge like this:
Map<String, Set<String>> map1; // [key="B";values=["Beryllium", "Boron", "Bromine"]]
Map<String, Set<String>> map2; // [key="B";values=["Bismuth"] key="I";values=["Iron"]]
for (Entry<String, Set<String>> entry : map2.entrySet()) {
map1.merge(entry.getKey(), entry.getValue(), (s1, s2) -> {s1.addAll(s2); return s1;});
}
//map1 = [key="B";values=["Beryllium", "Boron", "Bromine", "Bismuth"] key="I";values=["Iron"]]
Map::compute is probably what you're looking for. This gives you a way to map any existing value (if there is one), or provide one if not.
For example, in your case something like the following would probably suffice:
oldMap.compute("B", current -> {
if (current == null) {
// No existing entry, so use newMap's one
return newMap.get("B");
} else {
// There was an existing value, so combine the Sets
final Set<String> newValue = new HashSet<>(current);
newValue.addAll(newMap.get("B"));
return newValue;
}
});
There's also MultiValueMap and Multimap from spring and guava respectively (if you're ok bringing in dependencies) which cover this case with less work already.
Temporary map1 will not be needed in this case. Get the set for that character, if null create a new set. Add the word to that set and put in the map:
while (iterator.hasNext()) {
String word = iterator.next();
//some code
Set<String> words = map2.get(word.charAt(0));
if(words == null) {
words = new TreeSet<>();
}
words.add(word);
map2.put(word.charAt(0), words);
}
When using the merge() function, if the specified key is not already associated with a value or the value is null, it associates the key with the given value.
Otherwise, i.e if the key is associated with a value, it replaces the value with the results of the given remapping function. So in order to do not overwrite the old value you must write your remapping function so that it combines the old and new values.
To do so replace this line :
map2.putAll(map1);
with
map1.forEach( (key, value)->{
map2.merge(key, value, (value1,value2) -> Stream.of(value1,value2)
.flatMap(Set::stream)
.collect(Collectors.toSet()));
});
This will iterate over map1 and add echh key which is not present into map2 and associate it with the given value and for each key which is already present it combines the old values and new values.
Alternative you can also work with Map.computeIfPresent and Map.putIfAbsent
map1.forEach( (key, value)->{
map2.computeIfPresent(key, (k,v) -> Stream.of(v,value).flatMap(Set::stream).collect(Collectors.toSet()));
map2.putIfAbsent(key, value);
});

remove similar (redundant) strings from Arraylist

I'm trying to remove similar strings from an ArrayList but I'm getting this error:
CurrentModificationException
and here is my method where I pass my original arrayList (old) and get a new list without redundant strings.
ArrayList<String> removeRed(ArrayList<String> old) throws IOException
{
ArrayList<String> newList = new ArrayList<String>();
for (int i=0; i< old.size(); i++)
{
if(newList.size() < 1)
{
newList.add(old.get(0));
} else{
for(Iterator<String> iterator = newList.iterator(); iterator.hasNext();) {
while(iterator.hasNext())
{
if(!ChopMD((String) iterator.next()).equals(ChopMD(old.get(i))))
{
newList.add(old.get(i));
Log.e("new algo", "" + old.get(i) );
}
}
}
}
}}
Note that my ChopMD() returns a particular string and it works fine.
It works fine for the first few strings, this it throws that exception. Any suggestion to resolve this issue would be appreciated it. Thanks.
If you have no problems with using the standard library (always preferable, why reinvent the wheel) try
List<String> uniques = new ArrayList<String>(new HashSet<String>(oldList));
The HashSet will only contain unique strings and the ArrayList constructor takes any Collection (including a HashSet) to build a list from.
Judging from your comments it seems like you are trying to implement an Associative Array with unique keys using an ArrayList. The better approach is to use a Map implementation like HashMap to pair IDs with their associated Strings.
Map<Integer, String> map = new HashMap<>();
map.put(1, "This string corresponds to ID=1");
map.put(3, "Donald Ducks Nephews");
map.put(7, "Is a Prime");
Then to get a value associated with an ID:
int key = someObject.getID();
String value = map.get(key);
All the Map implementations use unique keys so there is no need for you to check for redundant IDs, if you try to add a new (key,value) pair the value associated with the ID will be replaced if the map contains the key.
map.put(1, "New String");
String s = map.get(1); //s will no longer be "This string corresponds to ID=1"
If you don't want this behavior you have the choice of either subclassing one of the Map implementations to ignore .put(key, value) if the map contains key,value or delegating .put(key,value) to some other class.
Subclassing:
public class UniqueValueHashMap<K,V> extends HashMap<K, V>{
#Override
public V put(K key, V value) {
if (containsKey(key))
return null;
return super.put(key, value);
}
Delegating
public class SomeClass {
private Map<Integer, String> map = new HashMap<>();
// ...stuff this class does
public String put(int key, String value) {
if (map.containsKey(key))
return null;
return map.put(key, value);
}
// ...more stuff this class does
}
Delegation is the better approach, notice how you can change the map implementation (using maybe a TreeMap instead of HashMap) without introducing a new class where you override the .put(key,value) of TreeMap.
You can iterate much easier by this
for (String oldString : old){
for (String newString : newList){
}
}
Also you can use Set to have unique strings
Set<String> newList = new HashSet<String>();
Your error is because you are changing the list WHILE it is still iterated.

Java HashMap: How to get a key and value by index?

I am trying to use a HashMap to map a unique string to a string ArrayList like this:
HashMap<String, ArrayList<String>>
Basically, I want to be able to access the keys by number, not by using the key's name. And I want to be able to access said key's value, to iterate over it. I'm imagining something like this:
for(all keys in my hashmap) {
for(int i=0; i < myhashmap.currentKey.getValue.size(); i++) {
// do things with the hashmaps elements
}
}
Is there an easy way to do this?
Here is the general solution if you really only want the first key's value
Object firstKey = myHashMap.keySet().toArray()[0];
Object valueForFirstKey = myHashMap.get(firstKey);
You can iterate over keys by calling map.keySet(), or iterate over the entries by calling map.entrySet(). Iterating over entries will probably be faster.
for (Map.Entry<String, List<String>> entry : map.entrySet()) {
List<String> list = entry.getValue();
// Do things with the list
}
If you want to ensure that you iterate over the keys in the same order you inserted them then use a LinkedHashMap.
By the way, I'd recommend changing the declared type of the map to <String, List<String>>. Always best to declare types in terms of the interface rather than the implementation.
HashMaps are not ordered, unless you use a LinkedHashMap or SortedMap. In this case, you may want a LinkedHashMap. This will iterate in order of insertion (or in order of last access if you prefer). In this case, it would be
int index = 0;
for ( Map.Entry<String,ArrayList<String>> e : myHashMap.iterator().entrySet() ) {
String key = e.getKey();
ArrayList<String> val = e.getValue();
index++;
}
There is no direct get(index) in a map because it is an unordered list of key/value pairs. LinkedHashMap is a special case that keeps the order.
Kotlin HashMap Answer
You can get key by index. Then get value by key.
val item = HashMap<String, String>() // Dummy HashMap.
val keyByIndex = item.keys.elementAt(0) // Get key by index. I selected "0".
val valueOfElement = item.getValue(keyByIndex) // Get value.
You can do:
for(String key: hashMap.keySet()){
for(String value: hashMap.get(key)) {
// use the value here
}
}
This will iterate over every key, and then every value of the list associated with each key.
A solution is already selected. However, I post this solution for those who want to use an alternative approach:
// use LinkedHashMap if you want to read values from the hashmap in the same order as you put them into it
private ArrayList<String> getMapValueAt(LinkedHashMap<String, ArrayList<String>> hashMap, int index)
{
Map.Entry<String, ArrayList<String>> entry = (Map.Entry<String, ArrayList<String>>) hashMap.entrySet().toArray()[index];
return entry.getValue();
}
for (Object key : data.keySet()) {
String lKey = (String) key;
List<String> list = data.get(key);
}
I came across the same problem, read a couple of answers from different related questions and came up with my own class.
public class IndexableMap<K, V> extends HashMap<K, V> {
private LinkedList<K> keyList = new LinkedList<>();
#Override
public V put(K key, V value) {
if (!keyList.contains(key))
keyList.add(key);
return super.put(key, value);
}
#Override
public void putAll(Map<? extends K, ? extends V> m) {
for (Entry<? extends K, ? extends V> entry : m.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
#Override
public void clear() {
keyList.clear();
super.clear();
}
public List<K> getKeys() {
return keyList;
}
public int getKeyIndex(K key) {
return keyList.indexOf(key);
}
public K getKeyAt(int index) {
if (keyList.size() > index)
return keyList.get(index);
return null;
}
public V getValueAt(int index) {
K key = getKeyAt(index);
if (key != null)
return get(key);
return null;
}
}
Example (types are differing from OPs question just for clarity):
Map<String, Double> myMap = new IndexableMap<>();
List<String> keys = myMap.getKeys();
int keyIndex = myMap.getKeyIndex("keyString");
String key = myMap.getKeyAt(2);
Double value myMap.getValueAt(2);
Keep in mind that it does not override any of the complex methods, so you will need to do this on your own if you want to reliably access one of these.
Edit: I made a change to the putAll() method, because the old one had a rare chance to cause HashMap and LinkedList being in different states.
Try this:
myhashmap.entrySet()
.forEach{
println(it.getKey())
println(it.getValue())
}
or if you want by index
myhashmap.entrySet()[0].getKey()
myhashmap.entrySet()[0].getValue()
myhashmap.entrySet()[1].getKey()
myhashmap.entrySet()[1].getValue()
HashMaps don't keep your key/value pairs in a specific order. They are ordered based on the hash that each key's returns from its Object.hashCode() method. You can however iterate over the set of key/value pairs using an iterator with:
for (String key : hashmap.keySet())
{
for (list : hashmap.get(key))
{
//list.toString()
}
}
If you don't care about the actual key, a concise way to iterate over all the Map's values would be to use its values() method
Map<String, List<String>> myMap;
for ( List<String> stringList : myMap.values() ) {
for ( String myString : stringList ) {
// process the string here
}
}
The values() method is part of the Map interface and returns a Collection view of the values in the map.
You can use Kotlin extension function
fun LinkedHashMap<String, String>.getKeyByPosition(position: Int) =
this.keys.toTypedArray()[position]
fun LinkedHashMap<String, String>.getValueByPosition(position: Int) =
this.values.toTypedArray()[position]
You'll need to create multiple HashMaps like this for example
Map<String, String> fruitDetails = new HashMap();
fruitDetails.put("Mango", "Mango is a delicious fruit!");
fruitDetails.put("Guava" "Guava is a delicious fruit!");
fruitDetails.put("Pineapple", "Pineapple is a delicious fruit!");
Map<String, String> fruitDetails2 = new HashMap();
fruitDetails2.put("Orange", "Orange is a delicious fruit!");
fruitDetails2.put("Banana" "Banana is a delicious fruit!");
fruitDetails2.put("Apple", "Apple is a delicious fruit!");
// STEP 2: Create a numeric key based HashMap containing fruitDetails so we can access them by index
Map<Integer, Map<String, String>> hashMap = new HashMap();
hashMap.put(0, fruitDetails);
hashMap.put(1, fruitDetails2);
// Now we can successfully access the fruitDetails by index like this
String fruit1 = hashMap.get(0).get("Guava");
String fruit2 = hashMap.get(1).get("Apple");
System.out.println(fruit1); // outputs: Guava is a delicious fruit!
System.out.println(fruit2); // outputs: Apple is a delicious fruit!

Categories

Resources