How to make class executable in forEach loop? - java

If I have a class
public class Op {
public Map<String, String> ops;
}
How can I make it executable in forEach loop?
for (String key : op) {
System.out.println(op.ops.get(key))
}
UPD
Here is my solution
Op op = new Op(new HashMap<String, String>() {{
put("a", "1");
put("b", "2");
put("c", "3");
}});
for (String key : op) System.out.println(op.map.get(key));
class Op implements Iterable<String> {
Map<String, String> map;
public Op(Map<String, String> map) {
this.map = map;
}
public Iterator<String> iterator() {
return map.keySet().iterator();
}
}
But I'm not sure about verbosity. Is it too verbose? Maybe there is a much concise way to implement it?

You are interested in looping over a SetEntry list.
for (Map.Entry<String, String > entry : ops.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
// ...
}
Propable duplicate of: Iterate through a HashMap

In this exact case, use #entrySet, #keySet or #values as specified in the API docs.
In a general case, an object is iterable using the enhanced for loop, if it is implementing the interface Iterable. The most of the standard java collections are implementing this interface.

public class Op implements Iterable<Map.Entry<String,String>> {
public Map<String, String> ops;
#Override
public Iterator<Map.Entry<String,String>> iterator() {
return ops.entrySet().iterator();
}
}
Example:
for (Map.Entry<String, String> n : testOp){
System.out.println("Key: " + n.getKey() + " Value: " + n.getValue());
}

Related

Not an "unsafe operation" error: Incompatible types Object cannot be converted to Entry<String, Boolean>

I have a Map in a class where I store a String key and a boolean value. Then, I return the map from the function getMap().
public class FacilityMachines {
private static Map<String, Boolean> map = new HashMap<String, Boolean>();
public Map getMap(){
return map;
}
In the class below, I'm trying to fetch that map, and then save it to an external file, I also instantiate FacilityMachines there:
public class WriteFile {
FacilityMachines fm = new FacilityMachines();
private Map<String, Boolean> m = new HashMap<String, Boolean>();
}
In WriteFile, I'm trying to parse the map into a new HashMap:
public void saveFacilityInfo() {
for (Map.Entry<String, Boolean> j: fm.getMap().entrySet()){
String s = j.getKey();
boolean b = j.getValue();
oStream.println(i + ": " + s + " = " + b + ". ");
}
}
oStream is just the variable for my PrintWriter.
The above yields Object cannot be converted to Entry<String, Boolean> error.
If I change the method signature of saveFacilityInfo to saveFacilityInfo(FacilityMachines fm), and then use the fm variable to try to fetch the map at the line for (Map.Entry<String, Boolean> j: fm.getMap().entrySet()) then I get a cannot find symbol on all the functions from the Entry interface: entrySet(), getKey(), and getValue().
And before anyone asks, I've imported HashMap and Map, and also tried using only import java.util.*; to import everything just in case.
I've also tried extending FacilityMachines from WriteFile and got the same results.
You need to return the map on the FacilityMachines class getMap() method with the correct type
public class FacilityMachines {
private static Map<String, Boolean> map = new HashMap<String, Boolean>();
public Map<String, Boolean> getMap(){
return map;
}
}

Complile error ConcurrentModificationException, trying to use method for removing the same names

Im trying to make my removeItemFromMapByValue method work together with removeItemFromMapByValue, but when i start to compile my code i get that ConcurrentModificationException. removeItemFromMapByValue have to remove the same names in values.
public class Solution
{
public static HashMap<String, String> createMap()
{
HashMap<String, String> map = new HashMap<String, String>();
map.put("Stallone", "Silvest");
map.put("Morikone", "Enio");
map.put("Vivaldi","Antonio");
map.put("Belucci", "Monica");
map.put("Gudini", "Harry");
map.put("Verdo", "Dhuzeppe");
map.put("Maracci", "Bruno");
map.put("Carleone", "Vito");
map.put("Bracco", "Luka");
map.put("Stradivari", "Antonio");
return map;
}
public static void removeTheFirstNameDuplicates(HashMap<String, String> map)
{
for (Map.Entry<String, String> pair : map.entrySet()){
String name = pair.getValue();
removeItemFromMapByValue(map, name);
}
}
public static void removeItemFromMapByValue(HashMap<String, String> map, String value)
{
HashMap<String, String> copy = new HashMap<String, String>(map);
for (Map.Entry<String, String> pair: copy.entrySet())
{
if (pair.getValue().equals(value))
map.remove(pair.getKey());
}
}
public static void main(String[] args)
{
HashMap<String, String> map = createMap();
removeTheFirstNameDuplicates(map);
System.out.println(map);
}
}
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:926)
at java.util.HashMap$EntryIterator.next(HashMap.java:966)
at java.util.HashMap$EntryIterator.next(HashMap.java:964)
at com.javarush.test.level08.lesson08.task05.Solution.removeTheFirstNameDuplicates(Solution.java:32)
at com.javarush.test.level08.lesson08.task05.Solution.main(Solution.java:52)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Process finished with exit code 1
The simple solution is to fix the first method, as this will avoid the error and behave correctly.
// remove any duplicated values, leaving one entry.
public static void removeTheFirstNameDuplicates(HashMap<String, String> map) {
Map<K,V> map2 = invert(invert(map));
map.clear();
map.putAll(map2);
}
public static <K, V> Map<V, K> invert(Map<K, V> map) {
Map<V, K> map2 = new HashMap<>();
for(Map.Entry<K< V> entry: map.entrySet())
map2.put(entry.getValue(), entry.getKey());
return map2;
}
Your compiler will not produce a ConcurrentModifcationException. You should look at the line in in the stack track to see where you are modifying the collection while iterating over it e.g.
for (Map.Entry<String, String> pair: copy.entrySet())
{
if (pair.getValue().equals(value))
map.remove(pair.getKey());
}
In this case you are removing an entry while iterating. A simple solution is to use the Iterator directly. Usually you IDE can do this refactoring.
for (Iterator<String> iter = copy.values().iterator(); iter.hasNext();) {
if (iter.next().equals(value))
iter.remove();
}
The problem with this solution is this is called from a nested and it will remove ALL matching entries as it does in your code. i.e. it will remove all the entries.
Here:
for (Map.Entry<String, String> pair : map.entrySet()){
String name = pair.getValue();
removeItemFromMapByValue(map, name); //you are about to delete a map item here!
}
You are modifying the Set that you are currently looping through ==> ConcurrentModificationException

How to remove duplication from my code

I have two similar methods. One of them prints something and one of them save somethings. As you can see there are a lot of duplicate code. How should I refactor it and remove this duplication ?
public static void printSomething(List<String> list) {
for (String item : list) {
if (item.contains("aaa")) {
System.out.println("aaa" + item);
}
if (item.contains("bbb")) {
System.out.println("bbb" + item);
} else {
System.out.println(item);
}
}
}
public static Map<String, String> getSomething(List<String> list) {
Map<String, String> map = new HashMap<String, String>();
for (String item : list) {
if (item.contains("aaa")) {
map.put("aaa", item);
}
if (item.contains("bbb")) {
map.put("bbb", item);
} else {
//do nothing
}
}
return map;
}
UPDATE:
Code was updated to solve problem when method are not exactly similar
Assuming the order of which the println of "aaa" and "bbb" appear does not matter, you could replace the implementation of printSomething with
public static void printSomething(List<String> list) {
Map<String, String> map = getSomething(list);
for(Map.Entry<String, String> entry : map) {
System.out.println(entry.getKey() + entry.getValue());
}
}
A generic Interface Action that have a method action(T t) can reduce the code.
public interface Action<E> {
void action(E e);
}
Example:
public static void forEach(List<String> list, Action <String> action) {
for(String s : list){
action.action(s);
}
Now you just need 2 different implementations of Action.
You can use annonymous types if you don't want to create a class.
If you know c# this is similar to lambdas.
edit:
Using annonymous type:
public static Map<String, String> getSomething(List<String> list) {
final Map<String, String> map = new HashMap<String, String>();
forEach(list, new Action<String>() {
#Override
public void action(String e) {
if (e.contains("aaa")) {
map.put("aaa", e);
}
if (e.contains("bbb")) {
map.put("bbb", e);
} else {
// do nothing
}
}
});
return map;
}
Creating the class:
public static Map<String, String> getSomething2(List<String> list) {
final Map<String, String> map = new HashMap<String, String>();
forEach(list, new ListToMapAction(map));
return map;
}
public class ListToMapAction implements Action<String> {
Map<String, String> map;
public ListToMapAction(Map<String, String> map) {
this.map = map;
}
#Override
public void action(String e) {
if (e.contains("aaa")) {
map.put("aaa", e);
}
if (e.contains("bbb")) {
map.put("bbb", e);
} else {
// do nothing
}
}
}
In a programming language with first-class functions, you'd pass around a function as a parameter indicating what you want to do inside the loop (for an example see the update, below). Java is going to have lambdas in version 8, but they're not quite up to the job.
In the current state of Java, you'll have to settle with something uglier - for example, passing an extra parameter to the method; or you could pass around anonymous inner classes that implement an interface, but IMHO that's even uglier than what I'm about to suggest:
static void printSomething(List<String> list, boolean print)
If print is true then print inside the loop, otherwise add to the Map. Of course, you'll have to add a couple of ifs inside the loop for checking this condition, and at the beginning, one extra if to determine if the Map is to be initialized. Either way, the method returns a Map, but the Map can be null for the printing case. This is what I mean:
static Map<String, String> processSomething(List<String> list, boolean print) {
Map<String, String> map = null;
if (!print)
map = new HashMap<String, String>();
for (String item : list) {
if (item.contains("aaa")) {
if (print)
System.out.println("aaa" + item);
else
map.put("aaa", item);
}
if (item.contains("bbb")) {
if (print)
System.out.println("bbb" + item);
else
map.put("bbb", item);
} else if (print) {
System.out.println(item);
}
}
return map;
}
UPDATE
For example, in Python - which allows passing functions as parameters, this is how you'd solve the problem in an elegant fashion:
def processSomething(lst, func):
result = None
for item in lst:
if 'aaa' in item:
result = func(item, 'aaa', result)
elif 'bbb' in item:
result = func(item, 'bbb', result)
else:
result = func(item, '', result)
return result
def printer(item, key, result):
print key + item
def mapper(item, key, result):
if not result:
result = {}
if key:
result[key] = item
return result
See how it works:
processSomething(['aaa', 'bbb', 'ccc'], printer)
=> aaaaaa
bbbbbb
ccc
processSomething(['aaa', 'bbb', 'ccc'], mapper)
=> {'aaa': 'aaa', 'bbb': 'bbb'}

iterator in a 2Dimensional Map

I would like to know how can I iterate in a 2Dimensional HashMap? I am creating an Object TrueStringMap2D that does the following: It will be a map 2D, i mean 2 keys and one value.
But the iterator implemented here is not functional.. i didnt know how to redefine the Iterator method in TrueStringMap2D :S (if possible should be remove in the iterator() functional)
Anyone can help?
Thankyou very much!!
I'll reinterpret the question into something similar that I enjoy answering, and then hopefully the answer to that question is useful to you.
Here's the question I'll answer:
How do I write an iterator that iterates over all values in a Map<String, Map<String, String>>?
This is how I would solve it:
class TwoDimIterator implements Iterator<String> {
Iterator<Map<String, String>> outerIter;
Iterator<String> innerIter = Collections.<String>emptyList().iterator();
public TwoDimIterator(Map<String, Map<String, String>> twoDimMap) {
outerIter = twoDimMap.values().iterator();
advanceInner();
}
#Override
public boolean hasNext() {
return innerIter.hasNext();
}
#Override
public String next() {
String toReturn = innerIter.next();
advanceInner();
return toReturn;
}
private void advanceInner() {
while (!innerIter.hasNext()) {
if (!outerIter.hasNext()) {
innerIter = Collections.<String>emptyList().iterator();
return;
}
innerIter = outerIter.next().values().iterator();
}
}
#Override
public void remove() {
throw new UnsupportedOperationException();
}
}
Test code:
class Test {
public static void main(String[] args) {
// Create a map
Map<String, Map<String, String>> twoDimMap =
new HashMap<String, Map<String, String>>();
// Fill it
Map<String, String> innerA = new HashMap<String, String>();
innerA.put("1", "A1");
innerA.put("2", "A2");
Map<String, String> innerB = new HashMap<String, String>();
innerB.put("1", "B1");
innerB.put("2", "B2");
twoDimMap.put("A", innerA);
twoDimMap.put("B", innerB);
// Create an iterator for the values:
Iterator<String> twoDimIter = new TwoDimIterator(twoDimMap);
while (twoDimIter.hasNext())
System.out.println(twoDimIter.next());
}
}
Output:
A2
A1
B2
B1

How do I access nested HashMaps in Java?

I have a HashMap in Java, the contents of which (as you all probably know) can be accessed by
HashMap.get("keyname");
If a have a HashMap inside another HashMap i.e. a nested HashMap, how would i access the contents? Can i do this like this, inline:
HashMap.get("keyname").get("nestedkeyname");
Thank you.
You can do it like you assumed. But your HashMap has to be templated:
Map<String, Map<String, String>> map =
new HashMap<String, Map<String, String>>();
Otherwise you have to do a cast to Map after you retrieve the second map from the first.
Map map = new HashMap();
((Map)map.get( "keyname" )).get( "nestedkeyname" );
You can get the nested value by repeating .get(), but with deeply nested maps you have to do a lot of casting into Map. An easier way is to use a generic method for getting a nested value.
Implementation
public static <T> T getNestedValue(Map map, String... keys) {
Object value = map;
for (String key : keys) {
value = ((Map) value).get(key);
}
return (T) value;
}
Usage
// Map contents with string and even a list:
{
"data": {
"vehicles": {
"list": [
{
"registration": {
"owner": {
"id": "3643619"
}
}
}
]
}
}
}
List<Map> list = getNestedValue(mapContents, "data", "vehicles", "list");
Map first = list.get(0);
String id = getNestedValue(first, "registration", "owner", "id");
Yes.
See:
public static void main(String args[]) {
HashMap<String, HashMap<String, Object>> map = new HashMap<String, HashMap<String,Object>>();
map.put("key", new HashMap<String, Object>());
map.get("key").put("key2", "val2");
System.out.println(map.get("key").get("key2"));
}
If you plan on constructing HashMaps with variable depth, use a recursive data structure.
Below is an implementation providing a sample interface:
class NestedMap<K, V> {
private final HashMap<K, NestedMap> child;
private V value;
public NestedMap() {
child = new HashMap<>();
value = null;
}
public boolean hasChild(K k) {
return this.child.containsKey(k);
}
public NestedMap<K, V> getChild(K k) {
return this.child.get(k);
}
public void makeChild(K k) {
this.child.put(k, new NestedMap());
}
public V getValue() {
return value;
}
public void setValue(V v) {
value = v;
}
}
and example usage:
class NestedMapIllustration {
public static void main(String[] args) {
NestedMap<Character, String> m = new NestedMap<>();
m.makeChild('f');
m.getChild('f').makeChild('o');
m.getChild('f').getChild('o').makeChild('o');
m.getChild('f').getChild('o').getChild('o').setValue("bar");
System.out.println(
"nested element at 'f' -> 'o' -> 'o' is " +
m.getChild('f').getChild('o').getChild('o').getValue());
}
}
As others have said you can do this but you should define the map with generics like so:
Map<String, Map<String, String>> map = new HashMap<String, Map<String,String>>();
However, if you just blindly run the following:
map.get("keyname").get("nestedkeyname");
you will get a null pointer exception whenever keyname is not in the map and your program will crash. You really should add the following check:
String valueFromMap = null;
if(map.containsKey("keyname")){
valueFromMap = map.get("keyname").get("nestedkeyname");
}
Yes, if you use the proper generic type signature for the outer hashmap.
HashMap<String, HashMap<String, Foo>> hm = new HashMap<String, HashMap<String, Foobar>>();
// populate the map
hm.get("keyname").get("nestedkeyname");
If you're not using generics, you'd have to do a cast to convert the object retrieved from the outer hash map to a HashMap (or at least a Map) before you could call its get() method. But you should be using generics ;-)
I prefer creating a custom map that extends HashMap. Then just override get() to add extra logic so that if the map doesnt contain your key. It will a create a new instance of the nested map, add it, then return it.
public class KMap<K, V> extends HashMap<K, V> {
public KMap() {
super();
}
#Override
public V get(Object key) {
if (this.containsKey(key)) {
return super.get(key);
} else {
Map<K, V> value = new KMap<K, V>();
super.put((K)key, (V)value);
return (V)value;
}
}
}
Now you can use it like so:
Map<Integer, Map<Integer, Map<String, Object>>> nestedMap = new KMap<Integer, Map<Integer, Map<String, Object>>>();
Map<String, Object> map = (Map<String, Object>) nestedMap.get(1).get(2);
Object obj= new Object();
map.put(someKey, obj);
I came to this StackOverflow page looking for a something ala valueForKeyPath known from objc. I also came by another post - "Key-Value Coding" for Java, but ended up writing my own.
I'm still looking for at better solution than PropertyUtils.getProperty in apache's beanutils library.
Usage
Map<String, Object> json = ...
public String getOptionalFirstName() {
return MyCode.getString(json, "contact", "firstName");
}
Implementation
public static String getString(Object object, String key0, String key1) {
if (key0 == null) {
return null;
}
if (key1 == null) {
return null;
}
if (object instanceof Map == false) {
return null;
}
#SuppressWarnings("unchecked")
Map<Object, Object> map = (Map<Object, Object>)object;
Object object1 = map.get(key0);
if (object1 instanceof Map == false) {
return null;
}
#SuppressWarnings("unchecked")
Map<Object, Object> map1 = (Map<Object, Object>)object1;
Object valueObject = map1.get(key1);
if (valueObject instanceof String == false) {
return null;
}
return (String)valueObject;
}
import java.util.*;
public class MyFirstJava {
public static void main(String[] args)
{
Animal dog = new Animal();
dog.Info("Dog","Breezi","Lab","Chicken liver");
dog.Getname();
Animal dog2= new Animal();
dog2.Info("Dog", "pumpkin", "POM", "Pedigree");
dog2.Getname();
HashMap<String, HashMap<String, Object>> dogs = new HashMap<>();
dogs.put("dog1", new HashMap<>() {{put("Name",dog.name);
put("Food",dog.food);put("Age",3);}});
dogs.put("dog2", new HashMap<>() {{put("Name",dog2.name);
put("Food",dog2.food);put("Age",6);}});
//dogs.get("dog1");
System.out.print(dogs + "\n");
System.out.print(dogs.get("dog1").get("Age"));
}
}
Example Map:
{
"data": {
"userData": {
"location": {
"city": "Banja Luka"
}
}
}
}
Implementation:
public static Object getValueFromMap(final Map<String, Object> map, final String key) {
try {
final String[] tmpKeys = key.split("\\.");
Map<String, Object> currentMap = map;
for (int i = 0; i < tmpKeys.length - 1; i++) {
currentMap = (Map<String, Object>) currentMap.get(tmpKeys[i]);
}
return currentMap.get(tmpKeys[tmpKeys.length - 1]);
} catch (Exception exception) {
return null;
}
}
Usage:
final Map<String, Object> data = new HashMap<>();
final Map<String, Object> userData = new HashMap<>();
final Map<String, Object> location = new HashMap<>();
location.put("city", "Banja Luka");
userData.put("location", location);
data.put("userData", userData);
System.out.println(getValueFromMap(data, "userData.location.city"));
Result:
Banja Luka
Process finished with exit code 0
I hit this discussion while trying to figure out how to get a value from a nested map of unknown depth and it helped me come up with the following solution to my problem. It is overkill for the original question but maybe it will be helpful to someone that finds themselves in a situation where you have less knowledge about the map being searched.
private static Object pullNestedVal(
Map<Object, Object> vmap,
Object ... keys) {
if ((keys.length == 0) || (vmap.size() == 0)) {
return null;
} else if (keys.length == 1) {
return vmap.get(keys[0]);
}
Object stageObj = vmap.get(keys[0]);
if (stageObj instanceof Map) {
Map<Object, Object> smap = (Map<Object, Object>) stageObj;
Object[] skeys = Arrays.copyOfRange(keys, 1, keys.length);
return pullNestedVal(smap, skeys);
} else {
return null;
}
}

Categories

Resources