Using Hashmap contains method to check for a duplicate key - java

So i have an interface.
public interface ARecord {
public BigInteger getAutoID();
public String getACompId();
}
and
public class APPPRecord extends AbstratAPRecord implements ARecord{
private BigInteger autoID;
private String ACompId = null;
//setter and getter}
In service,
List<APPPRecord> PFRecord = null;
while(scroll.next()){
APPPRecord item = (APPPRecord) scroll.get(0);
List<ARecord> recs = new ArrayList<ARecord>();
recs.addAll(PFRecord);
My PFRecord list has results that are being duplicated. I have to use hash maps that can check for ACompId contains key. If the key already exists don't pass it to recs.addAll. How can I go about doing this? Any help appreciated
Update: I tried Set and still see duplicate results with HashCode() and equals() in my model class.
for(ARecord records:recs){
uniqueRecs.put(records.getACompId(), records);
Set<String> keys = uniqueRecs.keySet();
for(String key: keys){
log.debug("keys " + key);
}
}
Also tried hashMaps.
HashMap<String, ARecord > uniqueRecs = new HashMap<String, ARecord >();
for(ARecord records:recs){
if(!uniqueRecs.containsKey(records.getACompId())){
uniqueRecs.put(records.getACompId(), records);
for (String key : uniqueRecs.keySet()) {
log.debug("unique record " + key);
}
}
}
Both of them still produce duplicate results. Any ideas?

Replace List<ARecord> recs = new ArrayList<ARecord>();
with Set<ARecord> recs = new HashSet<ARecord>();
and make sure the implementations of the ARecord implements the hashcode/equals methods properly so that your set only contains distinct instances.

Make use of HashMap<K,V> class, This document will provide you with the required API.
And according to your requirement you can make use of .containsKey(Object key) method to check for the existence of the key already.
Update: I suggested this because you asked for HashMap, if duplication is the only issue you have then you can make use of .contains(Object o) method on the List you already have in-place. the interface List<> provides this method which returns a boolean value based on the presence of the value.

Related

HashMap getting key given that I already have the key

This sounds like a really weird request but I have a HashMap of a custom class. I've overridden the equals and hashCode methods to only focus on certain fields, so that I can pull a key if it equals a new key with the same certain fields. In that case, I want to replace the other fields with some new values. The structure is like so:
public class ExampleClass() {
int field1;
int field2;
<insert constructor here with field1 and field2>
#Override
public boolean equals(Object obj) { // Only return true if field1 is equal
...
return (this.field1 == obj.field1);
}
}
So I use it like this:
HashMap<ExampleClass, int> hmap = new HashMap<>();
while(true) {
...
ExampleClass oldObject = new ExampleClass(1, 2);
ExampleClass newObject = new ExampleClass(1, 5);
hmap.put(oldObject, 10);
if(hmap.contains(newObject)) {
// Get field1 of old object and change it
}
}
This was a bad example but I just want to be able to retrieve the key object of a key-value pair in a HashMap given that I have the key so that I can modify the key. How would I do so?
Edit: My hashcode function.
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result +
((this.srcVertex.getVertexData().getID() == null) ? 0 : this.srcVertex.getVertexData().getID().hashCode());
result = prime * result +
((this.targetVertex.getVertexData().getID() == null) ? 0 : this.targetVertex.getVertexData().getID().hashCode());
return result;
}
As I understand your question, you have a key object in the HashMap, and you want to use an "equal" key object to retrieve the key rather than the value it's associated with. There is no method on a HashMap to do that, and it somewhat violates the idea of two objects being "equal" if you do actually care which of the two equal objects you get.
I think it would make more sense to do this in a different way:
Write a new class ExampleKey with just the fields that you want to use in the equals/hashCode methods for the purposes of the HashMap. This class must override equals and hashCode using those fields, and it should be immutable (the behaviour is undefined if a key's hash can change while it's in the HashMap).
Give ExampleClass a getKey() method which returns an ExampleKey object for the current object. It is probably simpler to use composition here, so that ExampleClass doesn't duplicate those fields.
Now have two HashMaps: a Map<ExampleKey, Integer> for the actual mapping that you want to store, and a separate Map<ExampleKey, ExampleClass> storing the object which would otherwise have been used as the key in the other HashMap.
Example usage:
Map<ExampleKey, Integer> actualMapping = new HashMap<>();
Map<ExampleKey, ExampleClass> objsUsed = new HashMap<>();
while(true) {
// ...
ExampleClass oldObject = new ExampleClass(1, 2);
ExampleClass newObject = new ExampleClass(1, 5);
// always update both maps together, to ensure valid state
actualMapping.put(oldObject.getKey(), 10);
objsUsed.put(oldObject.getKey(), oldObject);
// ...
ExampleClass objUsed = objsUsed.get(newObject.getKey());
if(objUsed != null) {
// objUsed == oldObject here
}
}
If you don't care about the philosophy of what "equal" is supposed to mean, then you can apply this same solution without the ExampleKey class or the getKey method; just use the objects themselves, i.e. objsUsed would be of type Map<ExampleClass, ExampleClass> and it would always map an object to itself. But I think if you do that, readers of your code will be scratching their heads wondering why you are mapping objects to themselves.
Maps in Java should be keyed on values that have equals defined over all their 'essential properties'. I believe most collection libraries work like this, with the only example that springs to mind is that of General Magic's Telescript.
So, have a Map defined on a type of only those properties. The field1 int (Integer) in this case. Put the rest of the information in the map entry value. This may well be a new class.
Map<Integer, ValueClass> map;
where
public final class ValueClass {
private int someValue;
private ExampleClass exmaple;
...
If you are insistent you want to find the key, which I suggest you don't. There's various ways of doing it, something like:
Optional<ExampleClass> found = map.keySet().stream()
.firstThat(k -> k.field1() == target);
found.ifPresent(key -> {
Integer value = hmap.remove(key);
// update key.
hmap.put(key, value);
});
Or the old school version (looks better to me, but not so cool):
for (ExampleClass key : map.keySet()) {
if (key.field1() == target) {
Integer value = hmap.remove(key);
// update key.
hmap.put(key, value);
}
}
Using an Iterator or possibly over an ihe entry set is better in that it avoids the second of three lookups, but I'll leave that as an exercise.
You forgot to define the hashCode() method. Without it, storing an object as a key in a HashMap doesn't work.
UPDATE:
If srcVertex is field1 and targetVertex is field2, then your hashCode() method is incorrect. If equals() compares srcVertex, then hashCode() should use only srcVertex, not targetVertex.
The rule is: if 2 objects are equal, then their hash codes must be equal.

Java Enum group enums by their values

Can you help me with solving some thing. I have enum in my java application:
public enum EnumKey {
ALPHA("group1"),
BETA("group2"),
GAMMA("group3"),
SIGMA("group2"),
DELTA("group2")
// and other values with "group1" or "group2" or "group3", constructors and getters
private String groupName;
}
I want to get something like Map<String, List<EnumKey>>, where keys is my specified groupNames and values is groupped and sorted by groupName enumKey list(I have only three specified groupNames). I hope my question is clear.
Hope you will help me to find an elegant way to do this.
This should generate the map you need:
public static Map<String, List<EnumKey>> crateEnumKeyMap() {
Map<String, List<EnumKey>> map = new HashMap<>();
for (EnumKey enumKey : EnumKey.values()) {
List<EnumKey> enumKeyList = map.get(enumKey.getGroupName());
if (enumKeyList == null) {
enumKeyList = new ArrayList<>();
map.put(enumKey.groupName, enumKeyList);
}
enumKeyList.add(enumKey);
}
return map;
}
Just create a map inside your EnumKey with the signature you yourself suggested.
In a static code block iterate over all the values in the enum and add them to the map by adding them to the appropriate list if it exists, if not creating the list and then adding it.

Get key from HashMap in Android by position or index

I have:
public static HashMap<String, String> CHILD_NAME_DOB = new HashMap<>();
Suppose the values in CHILD_NAME_DOB are:
<adam,15121990>
<roy,01051995>
<neha,05091992>
<alisha,11051992>
I am trying to fetch the last key element from CHILD_NAME_DOB. That is, I want to fetch key alisha from the example above to temporary String name.
Also I want to know on how to fetch data by index.
Eg.: if int index = 2 , I want key "Neha" in String name
TIA.
Edit: DateOfBirth value (value data in CHILD_NAME_DOB) is dynamic and is unknown. So THIS LINK is not what I want.
Single line solution:
First note that the Java HashMap does not guarantee the order of entries. So each time you iterate over a HashMap, entries appear in different positions. You will need LinkedHashMap that guarantees the predictable iteration order.
Map<String, String> CHILD_NAME_DOB = new LinkedHashMap<>();
Get the key by index:
key = (new ArrayList<>(CHILD_NAME_DOB.keySet())).get(index)
Get the value by index:
CHILD_NAME_DOB.get(key)
Thanks to #Pentium10 for this answer.
And I little modified it according to my need.
String key="default";
Iterator myVeryOwnIterator = CHILD_NAME_DOB.keySet().iterator();
while(myVeryOwnIterator.hasNext()) {
key=(String)myVeryOwnIterator.next();
//String value=(String)meMap.get(key);
}
Toast.makeText(viewEnterChildExp.getContext(), "Key: "+key , Toast.LENGTH_LONG).show();
I'm getting the last key element by this.
I'll update as soon I also get to find an easy way to key by index.
This way to get key....
public static String getHashMapKeyFromIndex(HashMap hashMap, int index){
String key = null;
HashMap <String,Object> hs = hashMap;
int pos=0;
for(Map.Entry<String, Object> entry : hs.entrySet())
{
if(index==pos){
key=entry.getKey();
}
pos++;
}
return key;
}
You can also use an ArrayMap instead of a HashMap. To get the value by index use:
ArrayMap.valueAt(index);
To get the Key at an index use:
ArrayMap.keyAt(index);
Fetching the "last" key and fetch by index is not supported by HashMap. You can use a LinkedHashMap and lookup the element with index 2 (or the last element) by iterating over it. But this will be a O(n) operation.
I suggest you use a List<Pair<String, String>> if the order of the keys/values is important to you and you wish to do index based lookup.
If both key based and index based lookup is important to you, you could use a combined data structure that consists of both a List and a HashMap, but note that removal of elements will be O(n).
You can create a class Child
public class Child(){
private String name;
private String number;
....
}
and then put this object in a List
public static List<Child> CHILD_NAME_DOB = new ArrayList<Child>(); // using LinkedList would defeat the purpose
in this way you can invoke the method get(int index), that returns the element at the specified position in this list.
In your example
<adam,15121990>
<roy,01051995>
<neha,05091992>
<alisha,11051992>
invoking CHILD_NAME_DOB.get(2) you'll get <neha,05091992>(as Child object)
HashMap does not have a concept of ordering, so getting the n-th entry does not make sense. You could use a TreeMap instead, which is ordered on its keys.
However, you should reconsider your model as you seem to have conflicting interests. On the one hand, accessing by index is typical for Lists, whereas accessing by key is typical for Maps. I'm not sure in which situation you'd want to do both.
If you really want to do both index and key accessing, you could write your own data structure that stores the data in a list combined with a mapping from key to index and vice versa. I would recommend against this, but if that's really what you want, then I think that's the best solution.
I know it is not the best solution, but what about this solution (pseudocode!). Just combine List and Map in one class.
public class UserBirthday {
private List<String> names = new ArrayList<>();
private Map<String, String> CHILD_NAME_DOB = new HashMap<String, String>();
public void add(String name, String bd) {
if (!CHILD_NAME_DOB.containsKey(name)) {
names.add(name);
}
CHILD_NAME_DOB.put(name, bd);
}
public String getByName(String name) {
return CHILD_NAME_DOB.get(name);
}
public String getByIndex(int index) {
return getByName(names.get(index)); // TODO: range test
}
public static void main(String[] args) {
UserBirthday ub = new UserBirthday();
ub.add("dit", "12345678");
ub.add("lea", "234239423");
ub.add("alex", "43534534");
ub.add("ted", "099098790");
System.out.println(ub.getByIndex(2));
System.out.println(ub.getByName("alex"));
}
}
You may get some problems if you remove an entry, but it should be just a suggestion.
for (String key : hmList.keySet()) {
String value = hmList.get(key);
Log.e("HashMap values", "key=" + key + " ,value=" + value);
}

Creating composite key for filtering data using Apache commons

Here is my problem
I have a list of 'System Exceptions' and I need to select distinct values from the list based on two keys. So I am creating a compositeKey and storing it in a list as a string 'key1:key2' Is there a better approach to this ?
Collection uniqueExceptions = CollectionUtils.select(allSubareaExceptions, new Predicate(){
private List<String> ids = new ArrayList<String>();
public boolean evaluate(Object obj) {
....domain.Exception ex = (....domain.Exception)obj;
String compositeKey = ex.getProcedure().getSubarea().getId() +":"+ex.getProcedure().getId();
if(ids.contains(compositeKey) == false){
ids.add(compositeKey);
return true;
}
return false;
}
});
There are several options. You could create a list:
List<String> compositKey = Arrays.asList(getSubareaId(), getProcedureId());
You could use an AbstractMap.SimpleEntry (1.6 or later only):
SimpleEntry<String, String> compositKey = new SimpleEntry(getSubareaId(), getProcedureId());
You could create your own pair implementation, or even a composite key class.
The major danger of using concatenation is if : is a legal character in the id strings, then you could get false duplicates.
you can override the equals() in the exception class to check on the "compositeKey". then create a Set off the list (set.addAll()) and there you go. u have a unique set of exceptions

What happens when a duplicate key is put into a HashMap?

If I pass the same key multiple times to HashMap’s put method, what happens to the original value? And what if even the value repeats? I didn’t find any documentation on this.
Case 1: Overwritten values for a key
Map mymap = new HashMap();
mymap.put("1","one");
mymap.put("1","not one");
mymap.put("1","surely not one");
System.out.println(mymap.get("1"));
We get surely not one.
Case 2: Duplicate value
Map mymap = new HashMap();
mymap.put("1","one");
mymap.put("1","not one");
mymap.put("1","surely not one");
// The following line was added:
mymap.put("1","one");
System.out.println(mymap.get("1"));
We get one.
But what happens to the other values? I was teaching basics to a student and I was asked this. Is the Map like a bucket where the last value is referenced (but in memory)?
By definition, the put command replaces the previous value associated with the given key in the map (conceptually like an array indexing operation for primitive types).
The map simply drops its reference to the value. If nothing else holds a reference to the object, that object becomes eligible for garbage collection. Additionally, Java returns any previous value associated with the given key (or null if none present), so you can determine what was there and maintain a reference if necessary.
More information here: HashMap Doc
You may find your answer in the javadoc of Map#put(K, V) (which actually returns something):
public V put(K key,
V value)
Associates the specified value with the specified key in this map
(optional operation). If the map
previously contained a mapping for
this key, the old value is replaced by
the specified value. (A map m is said
to contain a mapping for a key k if
and only if m.containsKey(k) would
return true.)
Parameters:
key - key with which the specified value is to be associated.
value - value to be associated with the specified key.
Returns:
previous value associated with specified key, or null if there was no
mapping for key. (A null return can also indicate that the map previously associated null with the specified key, if the implementation supports null values.)
So if you don't assign the returned value when calling mymap.put("1", "a string"), it just becomes unreferenced and thus eligible for garbage collection.
it's Key/Value feature and you could not to have duplicate key for several values because when you want to get the actual value which one of values is belong to entered keyin your example when you want to get value of "1" which one is it ?!that's reasons to have unique key for every value but you could to have a trick by java standard lib :
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public class DuplicateMap<K, V> {
private Map<K, ArrayList<V>> m = new HashMap<>();
public void put(K k, V v) {
if (m.containsKey(k)) {
m.get(k).add(v);
} else {
ArrayList<V> arr = new ArrayList<>();
arr.add(v);
m.put(k, arr);
}
}
public ArrayList<V> get(K k) {
return m.get(k);
}
public V get(K k, int index) {
return m.get(k).size()-1 < index ? null : m.get(k).get(index);
}
}
and you could to use it in this way:
public static void main(String[] args) {
DuplicateMap<String,String> dm=new DuplicateMap<>();
dm.put("1", "one");
dm.put("1", "not one");
dm.put("1", "surely not one");
System.out.println(dm.get("1"));
System.out.println(dm.get("1",1));
System.out.println(dm.get("1", 5));
}
and result of prints are :
[one, not one, surely not one]
not one
null
It replaces the existing value in the map for the respective key. And if no key exists with the same name then it creates a key with the value provided.
eg:
Map mymap = new HashMap();
mymap.put("1","one");
mymap.put("1","two");
OUTPUT
key = "1", value = "two"
So, the previous value gets overwritten.
The prior value for the key is dropped and replaced with the new one.
If you'd like to keep all the values a key is given, you might consider implementing something like this:
import org.apache.commons.collections.MultiHashMap;
import java.util.Set;
import java.util.Map;
import java.util.Iterator;
import java.util.List;
public class MultiMapExample {
public static void main(String[] args) {
MultiHashMap mp=new MultiHashMap();
mp.put("a", 10);
mp.put("a", 11);
mp.put("a", 12);
mp.put("b", 13);
mp.put("c", 14);
mp.put("e", 15);
List list = null;
Set set = mp.entrySet();
Iterator i = set.iterator();
while(i.hasNext()) {
Map.Entry me = (Map.Entry)i.next();
list=(List)mp.get(me.getKey());
for(int j=0;j<list.size();j++)
{
System.out.println(me.getKey()+": value :"+list.get(j));
}
}
}
}
Associates the specified value with the specified key in this map. If the map previously contained a mapping for the key, the old value is replaced.
To your question whether the map was like a bucket: no.
It's like a list with name=value pairs whereas name doesn't need to be a String (it can, though).
To get an element, you pass your key to the get()-method which gives you the assigned object in return.
And a Hashmap means that if you're trying to retrieve your object using the get-method, it won't compare the real object to the one you provided, because it would need to iterate through its list and compare() the key you provided with the current element.
This would be inefficient. Instead, no matter what your object consists of, it calculates a so called hashcode from both objects and compares those. It's easier to compare two ints instead of two entire (possibly deeply complex) objects. You can imagine the hashcode like a summary having a predefined length (int), therefore it's not unique and has collisions. You find the rules for the hashcode in the documentation to which I've inserted the link.
If you want to know more about this, you might wanna take a look at articles on javapractices.com and technofundo.com
regards
Maps from JDK are not meant for storing data under duplicated keys.
At best new value will override the previous ones.
Worse scenario is exception (e.g when you try to collect it as a stream):
No duplicates:
Stream.of("one").collect(Collectors.toMap(x -> x, x -> x))
Ok. You will get: $2 ==> {one=one}
Duplicated stream:
Stream.of("one", "not one", "surely not one").collect(Collectors.toMap(x -> 1, x -> x))
Exception java.lang.IllegalStateException: Duplicate key 1 (attempted merging values one and not one)
| at Collectors.duplicateKeyException (Collectors.java:133)
| at Collectors.lambda$uniqKeysMapAccumulator$1 (Collectors.java:180)
| at ReduceOps$3ReducingSink.accept (ReduceOps.java:169)
| at Spliterators$ArraySpliterator.forEachRemaining (Spliterators.java:948)
| at AbstractPipeline.copyInto (AbstractPipeline.java:484)
| at AbstractPipeline.wrapAndCopyInto (AbstractPipeline.java:474)
| at ReduceOps$ReduceOp.evaluateSequential (ReduceOps.java:913)
| at AbstractPipeline.evaluate (AbstractPipeline.java:234)
| at ReferencePipeline.collect (ReferencePipeline.java:578)
| at (#4:1)
To deal with duplicated keys - use other package, e.g:
https://google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/Multimap.html
There is a lot of other implementations dealing with duplicated keys.
Those are needed for web (e.g. duplicated cookie keys, Http headers can have same fields, ...)
Good luck! :)
I always used:
HashMap<String, ArrayList<String>> hashy = new HashMap<String, ArrayList<String>>();
if I wanted to apply multiple things to one identifying key.
public void MultiHash(){
HashMap<String, ArrayList<String>> hashy = new HashMap<String, ArrayList<String>>();
String key = "Your key";
ArrayList<String> yourarraylist = hashy.get(key);
for(String valuessaved2key : yourarraylist){
System.out.println(valuessaved2key);
}
}
you could always do something like this and create yourself a maze!
public void LOOK_AT_ALL_THESE_HASHMAPS(){
HashMap<String, HashMap<String, HashMap<String, HashMap<String, String>>>> theultimatehashmap = new HashMap <String, HashMap<String, HashMap<String, HashMap<String, String>>>>();
String ballsdeep_into_the_hashmap = theultimatehashmap.get("firststring").get("secondstring").get("thirdstring").get("forthstring");
}
BTW, if you want some semantics such as only put if this key is not exist. you can use concurrentHashMap with putIfAbsent() function.
Check this out:
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentHashMap.html#put(K,%20V)
concurrentHashMap is thread safe with high performance since it uses "lock striping" mechanism to improve the throughput.
Yes, this means all the 1 keys with value are overwriten with the last added value and here you add "surely not one" so it will display only "surely not one".
Even if you are trying to display with a loop, it will also only display one key and value which have same key.
HashMap<Emp, Emp> empHashMap = new HashMap<Emp, Emp>();
empHashMap.put(new Emp(1), new Emp(1));
empHashMap.put(new Emp(1), new Emp(1));
empHashMap.put(new Emp(1), new Emp());
empHashMap.put(new Emp(1), new Emp());
System.out.println(empHashMap.size());
}
}
class Emp{
public Emp(){
}
public Emp(int id){
this.id = id;
}
public int id;
#Override
public boolean equals(Object obj) {
return this.id == ((Emp)obj).id;
}
#Override
public int hashCode() {
return id;
}
}
OUTPUT : is 1
Means hash map wont allow duplicates, if you have properly overridden equals and hashCode() methods.
HashSet also uses HashMap internally, see the source doc
public class HashSet{
public HashSet() {
map = new HashMap<>();
}
}

Categories