How to improve performance of iteration through a HashMap in Java? - java

Does anybody have any idea about how I could improve the performance of this method? Note that this.allActions is a hashmap with around half a million keys.
Maybe there is a faster way of iterating through a HashMap that I don't know.
public String get_random_legal_action(String stateJSON) {
Collections.shuffle(this.allActionsKeys);
boolean legal;
HashMap<String, Integer> state = new Gson().fromJson(stateJSON, this.stateType);
for (String action : this.allActionsKeys) {
legal = true;
for (Map.Entry<String, Integer> precondition : this.allActions.get(action).precondition.entrySet()) {
try {
if (!state.get(precondition.getKey()).equals(precondition.getValue())) {
legal = false;
break;
}
} catch (NullPointerException e) {
if (!this.immutableProps.contains(precondition.getKey())) {
legal = false;
break;
}
}
}
if (legal)
return action;
}
return null;
}

Convert the HashMap to LinkedHashMap to improve the performance,
the complexity of Get O(1), Contains O(1) and Next O(1)
, You can create custom Key class and update hashCode() function
Use it in like LinkedHashMap<Key, Integer>
static class Key {
private static final int R = 256;
private static final long Q = longRandomPrime();
private String k;
public Key(String k) {
this.k = k;
}
public String key() {
return k;
}
#Override
public int hashCode() {
return Long.hashCode(hash());
}
#Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null)
return false;
if (getClass() != o.getClass())
return false;
Key other = (Key) o;
return k.equals(other.k);
}
#Override
public String toString() {
return k;
}
private long hash() {
long h = 0;
for (int j = 0; j < k.length(); j++) {
h = (R * h + k.charAt(j)) % Q;
}
return h;
}
private static long longRandomPrime() {
BigInteger prime = BigInteger.probablePrime(31, new Random());
return prime.longValue();
}
}

Related

Override deepEquals() method in Java without using Java.util.* method

There is something wrong with the deepEquals method in my ArrayDeque file, but I can not figure it out.
It should also make sense for LinkedListArrayDeque.
How to make the deepEquals work without using Java.util.* method?
The code below is about a double-ended array queue where the first item was added in the middle of the array.
I deleted several methods for brief view.
package deque;
import java.util.Iterator;
public class ArrayDeque<T> implements Deque<T>, Iterable<T> {
private T[] ts;
private int size;
private int stposition;
private int firposition;
private int lastposition;
public ArrayDeque() {
ts = (T[]) new Object[8];
size = 0;
stposition = Math.round(ts.length / 2);
firposition = stposition;
lastposition = stposition;
}
public T get(int i) {
if (size < i | size == 0) {
return null;
}
int pos = (firposition + i) % ts.length;
return ts[pos];
}
public int size() {
return size;
}
#Override
public Iterator<T> iterator() {
return new ArrayDequeIterator();
}
private class ArrayDequeIterator implements Iterator<T> {
private int pos0 = firposition;
public boolean hasNext() {
if (size == 0) {
return false;
}
if (pos0 == lastposition) {
return true;
}
if (size > 1) {
if (firposition < lastposition) {
if (pos0 < lastposition) {
return true;
}
} else {
if (pos0 + 1 < ts.length) {
return true;
}
}
return false;
}
return false;
}
public T next() {
T x = ts[pos0];
pos0 = (pos0 + 1) % ts.length;
return x;
}
}
#Override
public boolean equals(Object o) { // the equal method passed the tests but deepequal fail
if (o == this) {
return true;
}
if (o == null || this == null) {
return false;
}
if (!(o instanceof Deque)) {
return false;
}
Deque oll = (Deque) o;
if (oll.size() != this.size()) {
return false;
}
for (int i = 0; i < this.size(); i++) {
Object a2 = oll.get(i);
Object a1 = this.get(i);
if (a1 == a2) {
continue;
}
if (a2 == null) {
return false;
}
if (a1.getClass() != a2.getClass()) {
return false;
}
return deepEquals(a1, a2);
}
return true;
}
private boolean deepEquals(Object a1, Object a2) {
boolean deq;
if (a1 instanceof Deque) {
// maybe it's wrong here, I am not sure how to write this
deq = a1.equals(a2);
} else {
if (a1 == a2) {
return true;
}
return false;
}
return deq;
}
}
I finally figured it out. Thank for all the help.
It indeed doesn't not need another deepEqual method.
The equals method itself is enough.
The code is as follows:
(1. There is no iterator method in my deque interface, so I just used the get(i) method. But I can use it for this. Thanks for the advice from #knittl.
2. I think (!a1.equals(a2)) is important in my code.. I finally figured it out !...).
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (o == null) {
return false;
}
if (!(o instanceof Deque)) {
return false;
}
Deque oll = (Deque) o;
if (oll.size() != this.size()) {
return false;
}
int i = 0;
for (final Object a1 : this) {
Object a2 = oll.get(i);
i += 1;
if (a1 == a2) {
continue;
}
if (a2 == null) {
return false;
}
if (a1.getClass() != a2.getClass()) {
return false;
}
if (!a1.equals(a2)) {
return false;
}
}
return true;
}
You will want your equals method to compare each item in the list for equality. If two items are not equal, return false. Note that accessing an item in a linked list by index is O(n), meaning your equals method has quadratic runtime complexity. Use iterators to avoid that.
// ...
for (int i = 0; i < this.size(); i++) {
Object a2 = oll.get(i);
Object a1 = this.get(i);
if (!Objects.equals(a1, a2)) {
return false;
}
}
return true;
}
With iterators (which gives you linear runtime complexity):
// ...
Iterator<Object> otherIterator = oll.iterator();
for (final Object a1 : this) {
// guaranteed to work, because both lists have the same size:
final Object a2 = otherIterator.next();
if (!Objects.equals(a1, a2)) {
return false;
}
}
return true;
}

I need to implement a method where I can get key from value and method delete

I have a class MapEntry to implement Hashmap. I need to implement a method where I can get key from value and method delete. I know that HashMap does not implement such method as getValue but my prof asked to do this. I'm new to programming how it's a little bit hard for me right now. I'll appreciate any help.
public class MapEntry<K,V> {
MapEntry<K,V> next;
K key;
V value;
public MapEntry(K key, V value) {
this.setKey(key);
this.setValue(value);
}
public void setKey( K key){
this.key=key;
}
public void setValue(V value){
this.value=value;
}
public K getKey(){
return key;
}
public V getValue(){
return value;
}
public void setNext(MapEntry<K,V> next) {
this.next = next;
}
public MapEntry<K, V> getNext() {
return next;
}
}
public class HashMap{
private int DEFAULT_CAPACITY = 10;
private MapEntry<String,Double>[] Hash;
private int size;
public HashMap() {
Hash = new MapEntry[DEFAULT_CAPACITY];
}
public boolean isEmpty(){
if(size!= 0){
return false;
}
else{
return true;
}
}
public int getHashCode(String key){
int bucketIndex = key.hashCode()%Hash.length;
return bucketIndex;
}
public Double get(String key){
if(key == null){
try {
throw new IllegalAccessException("Null key");
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
MapEntry<String,Double> entry = Hash[getHashCode(key)];
while (entry != null && !key.equals(entry.getKey()))
entry = entry.getNext();
if(entry != null)
return entry.getValue();
else
return null;
}
}
public void put(String key, double value){
int keyBucket =hash(key);
MapEntry<String,Double> temp = Hash[keyBucket];
while (temp !=null){
if((temp.key == null && key == null)
|| (temp.key != null && temp.key.equals(key))){
temp.value = value;
return;
}
temp = temp.next;
}
Hash[keyBucket] = new MapEntry<String, Double>(key,value);
size++;
}
public void delete (String key) throws IllegalAccessException {
if(key == null){
throw new IllegalAccessException("Null key");
}
}
private int hash(String key){
if(key == null){
return 0;
}else {
return Math.abs(key.hashCode()% this.Hash.length);
}
}
public static void main(String[] args) {
HashMap hashMap = new HashMap();
hashMap.put("value", 2.2);
hashMap.put("bob", 2.3);
System.out.println(hashMap.get("value"));
System.out.println(hashMap.get("bob"));
System.out.println(hashMap.size);
System.out.println(hashMap.getHashCode("value"));
System.out.println(hashMap.getHashCode("bob"));
System.out.println(hashMap.isEmpty());
}
}
I think the basic algo will be :
Iterate through all the values one by one
If your value matches the desired result, retrieve the key from that entry.
To delete that entry, simply remove that entry
Note : Doesn't work properly if you have multiple entries of same value.

How can i access a private array with no getter Method from another class? [duplicate]

This question already has answers here:
How to read the value of a private field from a different class in Java?
(14 answers)
Closed 4 years ago.
So guys im trying to access a private Array from another class. Is there a way to access said array without a get-Method for the array?
public class Entity {
private int key;
private int value;
public Entity(int k, int v) {
key = k;
value = v;
}
public int getKey() {
return key;
}
public int getValue() {
return value;
}
public void setValue(int v) {
value = v;
}
public void setKey(int k) // selbst geadded
{
key = k;
}
}
Those are the elements that are contained in the array.
public class Relation {
private Entity[] map;
public Relation(int n) {
map = new Entity[n]; // größe des neuen feldes
}
public int size() {
return map.length;
}
public Entity extract(int i) {
if (i >= map.length || i < 0 || map[i] != null) {
return null;
}
int key = map[i].getKey();
int value = map[i].getValue();
map[i] = null;
return new Entity(key, value);
}
public boolean into(Entity e) {
for (int i = 0; i < size(); i++) {
if (map[i] == null) {
map[i] = e;
return true;
}
}
return false;
}
public static void main(String[] args) {
}
}
Relation is the Method im supposed to use. This class contains the private array which im trying to access.
public class Use {
public static boolean substitute(Relation rel, Entity e) {
if (rel.size() > 0) {
rel.map[0] = e; // "map has private acccess in Relation"
return true;
}
return false;
}
public static Relation eliminate(Relation rel, int k) {
int counter = 0;
for (int i = 0; i < rel.size(); i++) {
if (map[i] != k) // // "cannot find symbol map"
{
counter++;
}
}
}
}
And this is the class in which im trying to access the array. The methods here are not finished yet since im getting errors whenever im trying to access the map in the Relation class in any why since I cant figure it out.
To access fields, you need a FieldInfo:
Type relationType = typeof(Relation);
FieldInfo fieldRelationMap = relationType.GetField("map",
BindingFlags.Instance | BindingFlags.NonPublic);
FieldInfo has a GetValue and a SetValue

HashMap with ArrayLists values returning Null on Get() call

I have a HashMap that stores an object I created as a key and maps to an ArrayList of similar objects.
However, I am calling the get method, and using jGrasp's debugger I can clearly see that the key I am using in get() exists and indeed maps to an array but the only value I can get is a null value.
Here is where I am getting the null value.
public List<Entry> query(Record query) {
List<Entry> candList;
Entry key = new Entry(makeKey(query));
candList = map.get(key);
return candList;
}
Here is where I am populating the HashMap from a main store.
for(int i = 0; i < main.size(); i++) {
if(main.get(i).isActive()) {
values.clear();
tmp = new Entry(main.get(i).record());
key = new Entry(Record.make(tmp.entity(),tmp.relation(),wild));
if(!map.containsKey(key)) {
for(int v = 0; v < main.size(); v++) {
value = main.get(v);
if(key.entity().equals(value.entity()) && key.relation().equals(value.relation())) {
values.add(value);
}
}
map.put(key,new ArrayList(values));
}
}
}
Entry is a wrapper class that defaults to the equals() method of its inner object, here.
public boolean equals(Object o){
if(o == null){
return false;
}
else if(o instanceof Record){
Record r = (Record) o;
return this.entity.equals(r.entity) && this.relation.equals(r.relation) && this.property.equals(r.property);
}
else return false;
}
I also have a hashcode written for the object here.
int h = 0;
public int hashCode() {
int hash = h;
if(h != 0)
return hash;
String len = entity.concat(relation.concat(property));
for(int i = 0; i < len.length(); i++)
hash = hash * 31 +(int)len.charAt(i);
return hash;
}
For a little clarification, the Entry object holds an object of type Record that contains three immutable Strings, hence where the hashCode equation comes from.
For further clarification someone asked to see the entire Entry class.
private static class Entry {
private static boolean active;
private Record rec;
public Entry(Record r){
this.rec = r;
this.active = true;
}
public String entity() {
return rec.entity;
}
public String relation() {
return rec.relation;
}
public String property() {
return rec.property;
}
public Record record(){
return this.rec;
}
public boolean isActive(){
return this.active;
}
public void deactivate(){
this.active = false;
}
public void activate(){
this.active = true;
}
public boolean equals(Entry e) {
return this.rec.equals(e.record());
}
public int hashCode() {
return this.rec.hashCode();
}
public String toString() {
return rec.toString();
}
}
There are some collisions occurring in my HashMap but I know that's not supposed to be too much of an issue. Any ideas?
public boolean equals(Object o){
if(o == null){
return false;
}
else if(o instanceof Record){
Record r = (Record) o;
return this.entity.equals(r.entity) && this.relation.equals(r.relation) && this.property.equals(r.property);
}
else return false;
}
your Entry equals method may have some problem,what's the definition of relation?
the relation must be overwrite equals() and hashCode()
It's great to put all your code here,what's your main's definition?
and In your code there are many places contains maybe null pointer bug
your hashcode function might have a problem when setting the int to 0 (int h = 0) ... a good explanation can be found in Josh Bloch's Effectiv Java book (item 8).
Here is an example:
#Override
public int hashCode() {
int result = 17;
// this line should change depending on your fields
// let say you have a string property that is not null
result = 31 * result + property.hashCode();
return result;
}
... you can also use a library like Guava
#Override
public int hashCode() {
return Objects.hashCode(this.property1, this.property2);
}

Combining Hashtables without unifying interface

For a lot of implementation reasons (Using Java ME 1.4 with very limited libraries), I have no access to HashMap or any kind of Map interface. In combination with this, I have to use Hashtable, which in the libraries I'm using does not inherit anything.
Yes, there is absolutely no way for me to get around the implementation and libraries that I'm using.
So I have two Hashtables. I need to make one new Hashtable instance that accesses and changes the two "backing" instances. Since Hashtable does not inherit anything, is there any way I could do this? I've tried a rudimentary composing strategy that just goes through an array of tables, but there are some serious problems with that. Specifically, put(key, object) is difficult because there's no way to tell which map it is being backed to.
Any suggestions on a strategy to do this or am I stuck?
public class Scope {
private final Hashtable publicVars;
private final Hashtable publicMethods;
private final Hashtable publicReturning;
private final Hashtable privateVars;
private final Hashtable privateMethods;
public Scope() {
publicMethods = new Hashtable();
publicReturning = new Hashtable(0);
publicVars = new Hashtable();
privateVars = new Hashtable();
privateMethods = new Hashtable();
}
public Scope(Scope scope) {
publicVars = scope.publicVars;
publicMethods = scope.publicMethods;
publicReturning = scope.publicReturning;
privateVars = new Hashtable();
privateMethods = new Hashtable();
// Here's my problem - I need changes made to publicVars to also affect scope.privateVars (and the same to methods)
publicVars.putAll(scope.privateVars);
publicMethods.putAll(scope.privateMethods);
}
private static final class MapGroup {
private final List maps = new ArrayList();
public MapGroup(Hashtable start) {
maps.add(start);
}
public MapGroup(MapGroup group) {
for (int x = 0; x < group.maps.size(); x++) {
maps.add(group.maps.get(x));
}
}
public void add(Hashtable h) {
maps.add(h);
}
public Enumeration keys() {
return new Enumeration() {
private final Enumeration[] enumerations;
private int i;
{
enumerations = new Enumeration[maps.size()];
for (int x = 0; x < maps.size(); x++) {
enumerations[x] = ((Hashtable) maps.get(x)).keys();
}
}
public boolean hasMoreElements() {
return enumerations[i].hasMoreElements()
|| (++i < enumerations.length && enumerations[i].hasMoreElements());
}
public Object nextElement() {
// needed to increment i
return hasMoreElements() ? enumerations[i].nextElement() : null;
}
};
}
public Enumeration elements() {
return new Enumeration() {
private final Enumeration[] enumerations;
private int i;
{
enumerations = new Enumeration[maps.size()];
for (int x = 0; x < maps.size(); x++) {
enumerations[x] = ((Hashtable) maps.get(x)).elements();
}
}
public boolean hasMoreElements() {
return enumerations[i].hasMoreElements()
|| (++i < enumerations.length && enumerations[i].hasMoreElements());
}
public Object nextElement() {
// needed to increment i
return hasMoreElements() ? enumerations[i].nextElement() : null;
}
};
}
public boolean contains(Object value) {
for (int x = 0; x < maps.size(); x++) {
if (((Hashtable) maps.get(x)).contains(value)) {
return true;
}
}
return false;
}
public boolean containsKey(Object key) {
for (int x = 0; x < maps.size(); x++) {
if (((Hashtable) maps.get(x)).containsKey(key)) {
return true;
}
}
return false;
}
public Object get(Object key) {
for (int x = 0; x < maps.size(); x++) {
if (((Hashtable) maps.get(x)).containsKey(key)) {
return ((Hashtable) maps.get(x)).get(key);
}
}
return null;
}
public Object put(Object key, Object value) {
for (int x = 0; x < maps.size(); x++) {
if (((Hashtable) maps.get(x)).containsKey(key)) {
return ((Hashtable) maps.get(x)).put(key, value);
}
}
return ((Hashtable) maps.get(maps.size() - 1)).put(key, value);
}
public Object remove(Object key) {
// Nothing is ever removed - don't worry
return null;
}
public void clear() {
}
public int size() {
int s = 0;
for (int x = 0; x < maps.size(); x++) {
s += ((Hashtable) maps.get(x)).size();
}
return s;
}
public boolean isEmpty() {
return size() == 0;
}
}
Thanks for making me have to think about this guys. I wrote this and it works for me.

Categories