I need a Map impl which would consist of stacked maps, which I could push() and pop(), and the values would be "added" or "removed" if they belong to the map being pushed/popped. And the values would be searched top/bottom (or optionally bottom/top).
Is there an existing impl in JDK or elsewhere?
Example:
Stack
map4
foo => aaa
bar => 45
map3
bar => 22
map2
foo => ccc
baz => uuu
map1
For this, get("baz") would return "uuu", get("foo") would return "aaa", size() would return 3 etc.
It's something like JavaScript's prototypal inheritance.
There's one impl
I'm wishing for some more sophisticated impl, which wouldn't really go through all layers every time I call any method. Read methods are going to be more often than push()/pop(), so there could be some pre-computation during that.
You can have Stack as a wrapper. Have a Map<'String, Map> ( String here is for the name of the map). Expose push and pop as API. Interesting part of your question is, defining push and pop? How would the signature of these method actually look like? Actually, not very clear is to what you are trying to achieve?
So, there is no such builtin structure in the JDK, but it can be implemented using a LinkedList containing Maps.
LinkedList implements all three of List, Queue and Deque, maybe it's a little overkill, but ohwell...
A sample code would be as follows; however, the Map interface is not really obeyed (curious how you'd do .equals() and .hashCode() here? Not even talking about .clear()):
public final class StackedMap<K, V>
implements Map<K, V>
{
private final Map<K, V> NO_MAP = new HashMap<K, V>();
private final LinkedList<Map<K, V>> maps = new LinkedList<>();
private Map<K, V> currentMap = NO_MAP;
public void push(Map<K, V> map)
{
maps.push(map);
currentMap = map;
}
public Map<K, V> pop()
{
return currentMap = maps.pop();
}
#Override
public V get(K key)
{
V ret;
for (final Map<K, V> map: maps)
if ((ret = map.get(key)) != null)
break;
return ret;
}
// etc
}
Untested etc.
Related
Preface: This is not an actual problem that I have, it just came to my mind in a "What if... ...how would I do that?" fashion.
When I have Strings consisting of several key-value pairs (like 123=456;321=654;89=90), I can make a Map from that ({123=456, 321=654, 89=90}) pretty easily with a method like this:
public static Map<Integer, Integer> makeMap(String theString) {
String[] chunks = theString.split(";");
Map<Integer, Integer> result = new HashMap<>(chunks.length);
for (String chunk : chunks) {
String[] chunksChunks = chunk.split("=");
int key = Integer.parseInt(chunksChunks[0]);
int value = Integer.parseInt(chunksChunks[1]);
result.put(key, value);
}
return result;
}
Is there any elegant way to "widen" this method to be a generic method, accepting e.g. all (wrappers for) primitive types?
It would be possible to write...
public static <K extends Object, V extends Object> Map<K, V> makeMapGeneric(String theString) {
// ???
}
...but I have no idea how I would do the "castings" to the keys and values.
As far as I know, the primitive types do not have any common makeXYfromString(String ...) method, just explicit Integer.parseInt, Double.parseDouble and so on, and they do not have a common superclass/interface that I could restrict K and V to.
Giving the classes as argument (makeMapGeneric(String theString, Class<K> keyClass, Class<V> valueClass)) and writing something like K key = keyClass.cast(keyString);, isn't possible since you cannot cast a String to eg. an int, just parse it.
Is there any elegant solution possible?
I took a tought on it for a few minutes and i came up with this solution
public static <K, V> Map<K, V> makeMap(String input, Function<String, K> keyFunc, Function<String, V> valFunc) {
return Arrays.stream(input.split(";"))
.map(s -> s.split("="))
.collect(Collectors.toMap(s -> keyFunc.apply(s[0]), s -> valFunc.apply(s[1])));
}
You need to pass a two functions which will transform the string to the right value.
Use it like this:
Map<Integer, Integer> x = makeMap("123=456;321=654;89=90", Integer::parseInt, Integer::parseInt);
You could provide a Function to you method:
<K, V> Map<K, V> makeMapGeneric(String theString, Function<String, K> keyFn, Function<String, V> valueFn) {
String key = "123";
String value = "456";
K parsedKey = keyFn.apply(key);
V parsedValue = valueFn.apply(key);
}
Now you can call it with a Function that converts String to K (and V):
Map<Integer, Double> result =
makeMapGeneric("123=456", Integer::parseInt, Double::parseDouble);
I want your help for creating a data structure/ Collection which supports read and insert functionality and prevents deletion/removal of records.
One way i could think of is , to create a customized collection ( like myHashMap ) and override all the delete/remove methods and thus prevent removal/deletion of records? But this approach will not work if the Object is having removal method as Final.
Please suggest any better way ..!!!!
You can create your own arraylist by overriding the methods like remove() with unsupported operation exception. If you want you can also declare arraylist like this.
ArrayList<String> myList = new ArrayList<String>() {
#Override
public boolean remove(String str) {
//If you want, you can throw Unsupported operation exception also.
return false;
}
};
There may be some other good approaches, you can check answers from others also.
You can create your Map wrapper and provide only the methods you want to :
class MyHashMap<K, V> {
Map<K, V> map;
public MyHashMap(Map<K, V> map) {
this.map = map;
}
public V put(K key, V value) {
return map.put(key, value);
}
public V get(K key) {
return map.get(key);
}
// other methods you want
}
example:
MyHashMap<String, String> myMap = new MyHashMap<>(new HashMap<>());
log.info(m.differenceValue(jsonElement1,jsonElement2));
calling function from beanshell. The code implemented in jar file.
public static <K, V> Map<String,Object> differenceValue(JsonElement json1, JsonElement json2){
Gson g = new Gson();
Type mapType = new TypeToken<Map<String, Object>>(){}.getType();
Map<String,Object> firstMap = g.fromJson(json1, mapType);
Map<String, Object> secondMap = g.fromJson(json2, mapType);
return(mapDifference(firstMap,secondMap));
}
public static <K, V> Map<K, V> mapDifference(Map<? extends K, ? extends V> left, Map<? extends K, ? extends V> right) {
Map<K, V> difference = new HashMap<K, V>();
difference.putAll(left);
difference.putAll(right);
difference.entrySet().removeAll(right.entrySet());
return difference;
}
Is is working fine in eclipse but in jmeter it is throwing
error:Method info( java.util.HashMap ) not found in class'org.apache.log.Logger'
try log.info(m.differenceValue(jsonElement1,jsonElement2).toString());
according to documentation, that might work for HashMap (depending on what you have for the keys & values there)
public String toString()
Returns a string representation of this map.
The string representation consists of a list of key-value mappings in
the order returned by the map's entrySet view's iterator, enclosed in
braces ("{}"). Adjacent mappings are separated by the characters ", "
(comma and space). Each key-value mapping is rendered as the key
followed by an equals sign ("=") followed by the associated value.
Keys and values are converted to strings as by String.valueOf(Object).
You are trying to pass a Map to Logger while it accepts only Strings for info(), warn(), etc. methods to you will need to cast the Map to String somehow.
Also I don't think you have generics support in Beanshell, consider switching to JSR223 Elements and Groovy language instead.
I have a hashmap<String, String> which contains around one thousand entries.
Now I have to expose it in such way that it cannot be modified outside class. So I wrote like
public static Map<String, String> getResponseCodeSource()
{
return Collections.unmodifiableMap(codeMsgMap);
}
This method is called very frequently. My questions are 1. Will this cause performance issue? 2.Is method (unmodifiableMap) iterating over Map or this will perform its activity in O(constant) complexity ?
It's a very thin implementation:
public static <K,V> Map<K,V> unmodifiableMap(Map<? extends K, ? extends V> m) {
return new UnmodifiableMap<>(m);
}
and constructor code:
UnmodifiableMap(Map<? extends K, ? extends V> m) {
if (m==null)
throw new NullPointerException();
this.m = m;
}
So as you see complexity is O(1).
The Map returned from Collections.unmodifiableMap(Map) will be a thin proxy to the real underlying map with some methods disabled (put etc.). There is no reason to expect it to take a copy of the underlying map.
Returns: an unmodifiable view of the specified map.
Remember however that the unmodifiable map is only a view of the underlying map so changes in the underlying map will be reflected in the unmodifiable one. It would therefore be safe to do:
static final Map<String,String> codeMsgMap = new HashMap<>();
// Changes in the above map will be reflected here.
static final Map<String,String> unmodifiableCodeMsgMap = Collections.unmodifiableMap(codeMsgMap);
public static Map<String, String> getResponseCodeSource() {
return unmodifiableCodeMsgMap;
}
On the complexity question Sergey Pauk covers that nicely.
Is it possible to have a method requiring a HashMap and be able to provide any HashMap with Strings as keys? Some kind of generic data Type to put instead of 'Value'?
public void example(HashMap<String, Value> hashMap) {
//Stuff
}
example(new HashMap<String, Integer>);
HashMap<String, String> exampleMap = new HashMap<>();
example(exampleMap);
Alternatively, is it possible to check the key/value type of the map, other than looping through all the keys/value and check instanceof (without stopping it with return)?
public Boolean example(HashMap<String, Value> hashMap) {
for (Value value : hashMap.values())) {
if (value instanceof String) {
return true; //<- Unwanted
}
}
}
EDIT:
Let me explain my problem a bit further. I have a method:
public static Object getEIC(HashMap<String, Object> map, String key) {
for (String keys : map.keySet()) {
if (keys.equalsIgnoreCase(key)) {
return map.get(keys);
}
}
return null;
}
EIC stands for equalsIgnoreCase. So I need some generic return Type as well. Thanks for the answers so far, and thanks on forehand for the answers on this!
You could do:
HashMap<String, Object>
But that's terrible though because then you end up doing instanceof all the time. What you really need to do is understand what the key problem is and then think of inheritance. Can you define an interface that all your value objects would implement? For instance GeometricShape which could be implemented by Rectangle and Circle.
Also, you can define a HashMap as follows:
HashMap<String, ? extends SomeClass>
And as others pointed out, it's best to use the interface Map rather than a specific implementation e.g. HashMap.
Lastly, as I pointed out in a comment, it seems you are just trying to implement a Map<key, value> where you want to have case-insensitive keys. If so have a look at www.stackoverflow.com/questions/8236945/
The answer is to use a CaseInsensitiveMap. Thanks, everyone, for helping me and especially David Brossard for suggesting this.
You can implement the static method you are looking for using generics:
public static <V> V getEIC(Map<String, V> map, String key) {
for (String k : map.keySet()) {
if (k.equalsIgnoreCase(key)) {
return map.get(key);
}
}
return null;
}
however, you may wish to consider an enhanced Map Is there a good way to have a Map<String, ?> get and put ignoring case?
Note, however, that there is a subtle difference between this solution and using case-less equals - an ordinary Map<String,V> could hold a value for "Key" and "key" while a case-less Map would not. This method would arbitrarily choose one of them while a case-less Map would choose the most recent addition.
Yes, but requiring Map<String, Value> is better. If you don't care what value is ask for Map<String, ?>. If you do but don't yet know what it will be, use Map<String, ? extends T>
Requiring HashMap is programing to an implementation rather than an interface. There is rarely a good reason to do that.
And no. If you don't trust whoever built the map and want to be sure the map contains only the types it's supposed to contain you have to loop and check each one. However, you can abstract that away in a method that will check for you so you don't have to look at it.
public class CheckedCast
{
public static <K,V> Map<K,V> mapOf(Class<? extends K> classK,
Class<? extends V> classV,
Map<?,?> m)
{
for (Map.Entry<?, ?> e: m.entrySet())
{
classK.cast( e.getKey() );
classV.cast( e.getValue() );
}
#SuppressWarnings("unchecked")
Map<K,V> result = (Map<K,V>) m;
return result;
}
}