Dictionary of Objects where key is an instance field in Java - java

I was wondering if it was possible to have a Java dictionary of objects where one of the fields of the object is defined to be the key of the dictionary.
To be more specific, here's what I would like: I have defined a class with three fields. One of these fields is an Integer and is unique to each object. I would like this field to be the key of the dictionary.

Yes, of course it's possible.
Example :
Map<Integer,MyClass> map = new HashMap<Integer,MyClass>();
MyClass myObject = new MyClass(...);
map.put (myObject.getIntegerKey(), myObject);

If you want to hide the details:
public interface HasOwnKey<K> {
public K getKey();
}
public class MyMap<K, V extends HasOwnKey<K>> {
{
private Map<K,V> map = new HashMap<>();
public V put(V value) {
{
return this.map.put(value.getKey(),value);
}
public V get(K key) {
return this.map.get(key)
}
... etc
}
public class MyClass extends HasOwnKey<String> {
...
#Override String getKey() { return this.key; }
}
MyMap<String, MyClass> myMap = new MyMap<>();
MyClass obj = new MyClass();
obj.setKey("abc");
myMap.put(obj);
Unfortunately Java 7 doesn't seem to be smart enough to infer K from a declaration like
public class MyMap<V extends HasOwnKey<K>> {
so you have to provide the Key type in two places and cannot do
MyMap<MyClass> myMap = new MyMap<>();

You can do that easily as follows :
public class CustomClass
{
private int primaryKey;
private int secondaryField;
private int tertiaryField;
public CustomClass(int primaryKey, int secondaryField, int tertiaryField)
{
this.primaryKey = primaryKey;
this.secondaryField = secondaryField;
this.tertiaryField = tertiaryField;
}
public int getPrimaryKey(CustomClass object)
{
return object.primaryKey;
}
}
public class Test
{
public static void main(String[] args)
{
CustomClass object = new CustomClass(10, 20, 30);
Map map = new HashMap<Integer,CustomClass>();
map.put(object.getPrimaryKey(object), object);
}
}
You may also want to consider using Enums for doing the same, if the number of such records is fairly less, as they provide more readability.

If you already have created a List of those objects you can use an aggregate operation in java 8 like this:
Map<Integer, List<MyClass>> theMap = list
.stream()
.collect( Collectors.groupingBy(MyClass::myIntegerKey) );

Related

Java 8 - Map between class to one of its function

I have multiple types of objects, I'd like to generalise the 'id' of the objects in a way that will dynamically change what field is selected as the id.
Example
public class ObjectA{
//Attribute name attA
private String attA;
.... More attributes
public String getAttA(){
return attA
}
.....More getters/setters
}
public class ObjectB{
//Attribute named attB
private String attB;
.... More attributes
public String getAttB(){
return attB
}
.... More getters and setters
}
Id like to be able to run something like this:
Map<????, ????> customIdMap = new HashMap<>();
//We decide that ObjectA main attribute is AttA
customIdMap.add(ObjectA.class, ObjectA::getAttA);
//We decide that ObjectB main attribute is AttB
customIdMap.add(ObjectB.class, ObjectB::getAttB);
Then I'll be able to have a list of general objects and ill be able to retrieve their ids from the map if it is a known object with:
public String getCustomId(Object object){
if(customIdMap.contains(object.getClass()){
//Parameters are messed up, but this is the general idea of how
//i thought this would look
return customIdMap.get(object.getClass()).apply(object);
}
}
The code above does not run since getAttA is a call to a none static method in a static context so i assume this maybe should be wrapped in some kind of generic object.
Can it be done?
Preferably you change ObjectA and ObjectB to have a common interface. If that's not possible you can put them into a map like this:
Map<Class<? extends Object>, Function<Object, String>> map = new HashMap<>();
map.put(ObjectA.class, a -> ((ObjectA) a).getAttA());
map.put(ObjectB.class, b -> ((ObjectB) b).getAttB());
EDIT:
Or if you would like to encapsulate it into a typesafe heterogeneous container:
public static class ToIdMap {
private final Map<Class<?>, Function<Object, String>> map = new HashMap<>();
public <X> void put(Class<X> clazz, Function<X, String> func) {
map.put(clazz, (Function<Object, String>) func);
}
public String toIdString(Object o) {
return map.get(o.getClass()).apply(o);
}
}
EDIT2: Note that neither of these solutions work for subclasses, but it could be supported by traversing the class hierarchy in toIdString.
Your wording is a bit unclear, but I assume you want to get the ID of an object, even when they are different classes. This is the problem that interfaces solve.
You can create an interface, with one method called getId(), which will return the id. Then, you can just call getId() on any type of object with an id.
For example:
public interface Identifiable {
String getId();
}
public class ObjectA implements Identifiable {
// same for ObjectB
#Override
public String getId() {
return id;
}
}
Then, in your code:
Identifiable i1 = new ObjectA();
Identifiable i2 = new ObjectB();
System.out.println(i1.getId());
System.out.println(i2.getId());
EDIT:
It still looks like an interface is the cleanest way of solving your problem. For completeness, the following will work:
Map<Class, Function<?, String> map = new HashMap<>();
map.put(Object1.class, (Object1 o) -> o.getAttrA); // repeat for ObjectB
It can then be called with:
if (obj instanceof Object1) return map.get(Object1.class).apply((ObjectA) obj);
Ended up doing this weird solution:
class Mapping<T> {
private Function<T, String> idFunc;
public Mapping(Function<T, String> idFunc) {
this.idFunc = idFunc;
}
public String apply(T obj) {
return idFunc.apply(obj);
}
}
}
private Map<Class, Mapping> mappings = new HashMap<>();
mappings.put(ObjectA.class, new Mapping<>(ObjectA::getAttA);
mappings.put(ObjectB.class, new Mapping<>(ObjectB::getAttB);
public String getObjectID(Object object){
String id = null;
if(mappings.containsKey(object.getClass())){
id = mappings.get(object.getClass()).apply(object);
}
return id;
}

prevent protected variable access from child class without using getter and setter in java

Without using getter and setter method how to prevent modification access from child class if super class has protected Hashmap variable?
This Map is mutable (So i should be able to add the values from super class)So can't use UnmodifiableMap(its only applicable immutable collection object)
Class A
{
protected Map<Integer,Integer> m = new HashMap<Integer,Integer>();
A()
{
m.put(10,11)
m.put(11.12)
}
}
Class B extends A
{
B()
{
super.m.put(34,90) —— I don’t want to give access to child class to add
the value and child class and its only should able to get the values.
}
}
Make the map unmodifiable, and populate it in the construction of A.
class A {
protected final Map<Integer,Integer> m;
A() {
Map<Integer, Integer> tempMap = = new HashMap<>();
tempMap.put(10,11);
tempMap.put(11.12);
this.m = java.util.Collections.unmodifiableMap(tempMap);
}
}
If and when B attempts to modify the map, a ´UnsupportedOperationException´ will be thrown.
If you want A to be able to modify the map, then you'll need a different approach in which the map is private, and a protected getter returns an unmodifiable map.
class A {
private final Map<Integer,Integer> m = new HashMap<>();
A() {
m.put(10,11);
m.put(11.12);
// m remains modifiable within the context of A
}
protected Map<Integer, Integer> getMap() {
return java.util.Collections.unmodifiableMap(m);
}
}
EDIT
If you really don't want to use a getter but still have read-only access, you can use this approach.
class A {
private final Map<Integer,Integer> writableMap = new HashMap<>();
protected final Map<Integer,Integer> m = Collections.unmodifiableMap(writableMap);
A() {
writableMap.put(10,11);
writableMap.put(11.12);
}
}
Using this approach, only m is visible outside A, and is read-only. Within A, you can update writableMap and these changes will be visible in m
Here is a variant of what Steve Chaloner presented in his answer:
public class A {
private final Map<Integer, Integer> map = new HashMap<>();
protected final Map<Integer,Integer> m = Collections.unmodifiableMap(map);
public A() {
map.put(10, 11);
map.put(11, 12);
}
}
The private map is modifiable in the A class and changes will be reflected in the protected m whenever changes are made in map.
It is being used this way in Concurrency In Practice for example.
This should be the best solution Composition:
Implement a new Map and keep an internal private modifiable map like this:
class A {
private Map<Integer,Integer> m = new HashMap<>();
protected Map<Integer, Integer> map = new Map<>() {
//implement interface
public Integer put(Integer key, Integer value) {
throw new UnsupportedOperationException();
}
public Integer get(Object key) {
return m.get(key);
}
public void clear() {
throw new UnsupportedOperationException();
}
public boolean containsKey(Object key) {
return m.containsKey(key);
}
public boolean containsValue(Object value) {
return m.containsValue(value);
}
//
// ... And so on
//
// ... with all other methods
}
A() {
m.put(10,11)
m.put(11.12)
}
}
class B extends A {
B() {
super.map.put(34,90) // thorws exception
super.m.put(34,90) // inaccesible
}
}
All modifications are allowed in A via m but subclasses may only acces them by map that was succesfully blocked modifications.

Convert multiple if statements to dispatch functions

I am struggling to find a way to dispatch this to functions in java8
Person p = registry.getPerson();
if (field == Field.LASTNAME) {
p.setLastName(str);
}
if (field == Field.FIRSTNAME) {
p.setFirstName(str);
}
if (field == Field.MIDDLENAME) {
p.setMiddleName(str);
}
My idea is to use some kind of function dispatch table to replace the if statements in the case of more cases:
Map<Integer, Function> map = new HashMap<Integer, Function>
static {
map.put(1, new Function<String, String>() {
#Override
public Object apply(String str) {
person.setLastName(str);
return str;
}
}
}
But the code cannot compile, because i need to pass the person object some place. Anyone knows a pattern for this?
Assuming Field is an enum, you can add BiConsumer<Person,String> as an enum field:
class Person {
static enum Field {
FIRSTNAME(Person::setFirstName),
MIDDLENAME(Person::setMiddleName),
LASTNAME(Person::setLastName)
;
private BiConsumer<Person, String> setter;
private Field(BiConsumer<Person, String> setter) {
this.setter = setter;
}
}
public void set(Field field, String str) {
field.setter.accept(this, str);
}
......
}
Instead of storing Function<String,String>, you can store BiFunction<Person,String,String> and pass the Person instance in as a parameter.
Map<Integer, BiFunction<Person,String,String>> map =
new HashMap<Integer, BiFunction<Person,String,String>>();
static {
map.put(1, (person, str)->person.setLastName(str));
}
In the interest of simplicity, you could also just store a List of the functions, if you're just going to index them by an integer, it's faster for random access and makes for less complicated generic code:
List<BiFunction<Person,String,String>> list = new ArrayList<BiFunction<Person,String,String>>();
static {
list.add((person, str)->person.setLastName(str));
}

How to efficiently get the values from a HashMap with a static class?

I have a class with a HashMap<k,v>.
The type of the values of this HashMap is a static class which has two different objects as attributes. i.e.,
public class Example {
private HashMap<String, StaticClassExample> map;
private static class StaticClassExample {
private Object1 o1;
private Object2 o2;
//...
}
//...
}
And my question is how can I do this operation efficiently:
public List<Object1> getAllObject1() {}
I know that I can do: map.values() and then iterate the values collection and get Object1 from each StaticClassExample, but this wouldn't be efficient.
It's possible what I ask or I must create another hashmap for my purpose?
If you don't mind some memory overhead, you could keep a separate list with the o1-values:
public class HashMapList
{
private HashMap<String, StaticClassExample> map = new HashMap<String, HashMapList.StaticClassExample>();
private List<Object> o1List = new LinkedList<Object>();
public static class StaticClassExample
{
private Object o1;
private Object o2;
}
public void addStaticClassExample(String key, StaticClassExample example)
{
StaticClassExample oldVal = map.put(key, example);
if(oldVal != null)
{
o1List.remove(oldVal.o1);
}
o1List.add(example.o1);
}
public StaticClassExample getStaticClassExampleByKey(String key)
{
return map.get(key);
}
public void removeStaticClassExampleByKey(String key)
{
StaticClassExample removed = map.remove(key);
if(removed != null)
{
o1List.remove(removed.o1);
}
}
public List<Object> getAllObject1()
{
return Collections.unmodifiableList(o1List);
}
}
Of course, this requires you to encapsule the HashMap inside the class and never give a straight access to it, because then someone using the class could modify the HashMap directly, and the List would no longer be in sync with the Map. Note that getAllObject1 returns an unmodifiable view of the internal list, so it can't be modified from outside of the class.

Looking for a "chained map" implementation in Java

I need a mapping from a list of keys to a value. I know I could write my own code like this:
Map<Person, Map<Daytime, Map<Food, Integer>>> eaten = ...;
Now I want to have some get and put methods like these:
Integer numberOfEggsIAteInTheMorning = eaten.get(me, morning, scrambledEggs);
eaten.put(me, evening, scrambledEggs, 1);
Do you know of an existing class that has this kind of API? I'm too lazy of writing it myself. ;)
If you look for a more generic approach, and you might have more than 2 or 3 'chain steps', I would suggest in applying some different structural approach, rather than sticking to using only basic collection classes. I have feeling that Composite Pattern could be the right choice if it's correctly applied.
EDIT: due to example requested
The full example would be somewhat time consuming, so let me just explain my idea with dirty Java/pseudocode mix (I'm not even sure if I've missed something!!!). Let's consider we have class BaseMap:
abstract class BaseMap {
public abstract Object getValue(Object.. keys);
public abstract void putValue(Object value, Object.. keys);
}
Then we could have ObjectMap that would be the 'leaf' of our composite structure:
class ObjectsMap extends BaseMap {
private Map<Object, Object> map = new [...]
public Object getValue(Object.. keys) {
// assert that keys.length == 1
return map.get(keys[0]);
}
public void putValue(Object value, Object.. keys) {
// assert that keys.length = 1
map.put(keys[0], value);
}
}
And the actual composite would be as such:
class CompositeMap extends BaseMap {
private Map<Object, BaseMap> compositeMaps = new [...]
public Object getValue(Object.. keys) {
// assert that keys.length > 1
return compositeMap.get(keys[0]).getValue(/* System.arrayCopy => subset of elements {keys_1, .. ,keys_max} */);
}
public void putValue(Object value, Object.. keys) {
// assert keys.length > 1
BaseMap newMap = null;
if (keys.length = 2) -> newMap = new ObjectsMap()
else newMap = new CompositeMap();
newMap.putValue(value, /*subset of keys {keys_1, .. , keys_max}*/);
}
}
You can use org.apache.commons.collections.keyvalue.MultiKey for that: Map<Multikey, Object>
It would be hard to implement a general chained map.
How would the declaration of the class look like? (You can't have a variable number of type parameters.
class ChainedMap<K1..., V>
Another option would be to have a ChainedMapUtil class that performs put / get recursively.
Here is an example of a recursive get. (Quite ugly solution though I must say.)
import java.util.*;
public class Test {
public static Object chainedGet(Map<?, ?> map, Object... keys) {
Object k = keys[0];
if (!map.containsKey(k)) return null;
if (keys.length == 1) return map.get(k);
Object[] tailKeys = Arrays.copyOfRange(keys, 1, keys.length);
return chainedGet((Map<?,?>) map.get(k), tailKeys);
}
public static void main(String[] arg) {
Map<String, String> m1 = new HashMap<String, String>();
m1.put("ipsum", "dolor");
Map<Integer, Map<String, String>> m2 =
new HashMap<Integer, Map<String, String>>();
m2.put(17, m1);
Map<String, Map<Integer, Map<String, String>>> chained =
new HashMap<String, Map<Integer, Map<String, String>>>();
chained.put("lorem", m2);
System.out.println(chainedGet(chained, "lorem", 17, "ipsum")); // dolor
System.out.println(chainedGet(chained, "lorem", 19, "ipsum")); // null
}
}
If you are going to write your own, I would suggest
eaten.increment(me, evening, scrambledEggs);
You could use a composite key
eaten.increment(Key.of(me, evening, scrambledEggs));
(TObjectIntHashMap supports increment and adjust)
You may not even need a custom key.
eaten.increment(me + "," + evening + "," + scrambledEggs);
It is fairly easy to decompose the key with split()
I once made a map using 3 keys just for fun.May be you can use it instead of using chained maps:
public class ThreeKeyMap<K1,K2,K3,V>{
class wrap{
K1 k1;
K2 k2;
K3 k3;
public wrap(K1 k1,K2 k2,K3 k3) {
this.k1=k1;this.k2=k2;this.k3=k3;
}
#Override
public boolean equals(Object arg0) {
// TODO Auto-generated method stub
wrap o=(wrap)arg0;
if(!this.k1.equals(o.k1))
return false;
if(!this.k2.equals(o.k2))
return false;
if(!this.k2.equals(o.k2))
return false;
return true;
}
#Override
public int hashCode() {
int result=17;
result=37*result+k1.hashCode();
result=37*result+k2.hashCode();
result=37*result+k3.hashCode();
return result;
}
}
HashMap<wrap,V> map=new HashMap<wrap, V>();
public V put(K1 k1,K2 k2,K3 k3,V arg1) {
return map.put(new wrap(k1,k2,k3), arg1);
}
public V get(Object k1,Object k2,Object k3) {
return map.get(new wrap((K1)k1,(K2)k2,(K3)k3));
}
public static void main(String[] args) {
ThreeKeyMap<Integer,Integer,Integer,String> birthDay=new ThreeKeyMap<Integer, Integer, Integer, String>();
birthDay.put(1, 1,1986,"Emil");
birthDay.put(2,4,2009, "Ansih");
birthDay.put(1, 1,1986,"Praveen");
System.out.println(birthDay.get(1,1,1986));
}
}
UPDATE:
As #Arturs Licis suggested.I looked up in net for composite pattern and I wrote a sample using it.I guess this is composite..Please comment if it is not so.
Person class:
public class Person {
private final String name;
private Map<Time, Food> map = new HashMap<Time, Food>();
public Person(String name) {
this.name = name;
}
void addTimeFood(Time time, Food food) {
map.put(time, food);
}
public String getName() {
return name;
}
Food getFood(Time time) {
Food tmp = null;
return (tmp = map.get(time)) == null ? Food.NoFood : tmp;
}
// main to test the person class
public static void main(String[] args) {
Person p1 = new Person("Jack");
p1.addTimeFood(Time.morning, Food.Bread);
p1.addTimeFood(Time.evening, Food.Chicken);
Person p2 = new Person("Jill");
p2.addTimeFood(Time.morning, Food.Egg);
p2.addTimeFood(Time.evening, Food.Rice);
Map<String, Person> map = new HashMap<String, Person>();
map.put(p1.getName(), p1);
map.put(p2.getName(), p2);
System.out.println(map.get("Jack").getFood(Time.evening));
}
#Override
public String toString() {
StringBuilder b = new StringBuilder();
b.append(name).append("\n");
b.append(map);
return b.toString();
}
}
Food class:
public enum Food {
Rice,
Egg,
Chicken,
Bread,
NoFood;
}
Time class:
public enum Time {
morning,
evening,
night
}

Categories

Resources