Hi i have bytearrays of size 8 bytes each and i need to store them in a hashmap or hashtable. For example say i have 1000 blocks... then it will store 1st key and value(bytearray) and then when block2 is passed it should check if it is already present in hahtable and if not there it should increment and count should be incremented. I have written code to store but the problem is that it is not able to search, may be bacuse of the way i'm storing in byte array.
Code:
int collisions = 0;
Hashtable<Integer, Long> ht = new Hashtable<Integer, Long>();
// Given bloc1 value here
if(ht.contains(bloc1)) {
collisions++;
}
else {
ht.put(i,ByteBuffer.wrap(bloc1).getLong());
}
Problem is: ht.contains is not giving the desired o/p
byte[] objects, and other array objects in Java has equals() method inherited from Object, i. e. comparing by reference, not by array contents.
The simpliest way to resolve your problem (without additional dependencies to libraries) is to store 8-byte arrays as longs:
Map<Long, Value> map = new HashMap<>();
...
// map.put(byteArray, value);
map.put(ByteBuffer.wrap(byteArray).getLong(), value);
Solution:
int collisions = 0;
Hashtable ht = new Hashtable();
// Given bloc1 value here
if(ht.contains(ByteBuffer.wrap(bloc1).getLong()))
{collisions++;}
else {
ht.put(i,ByteBuffer.wrap(bloc1).getLong());
}
Related
If you had 1,000,000 keys (ints) that mapped to 10,000 values (ints). What would be the most efficient way (lookup performance and memory usage) to implement.
Assume the values are random. i.e there is not a range of keys that map to a single value.
The easiest approach I can think of is a HashMap but wonder if you can do better by grouping the keys that match a single value.
Map<Integer,Integer> largeMap = Maps.newHashMap();
largeMap.put(1,4);
largeMap.put(2,232);
...
largeMap.put(1000000, 4);
If the set of keys is known to be in a given range (as 1-1000000 shown in your example), then the simplest is to use an array. The problem is that you need to look up values by key, and that limits you to either a map or an array.
The following uses a map of values to values simply to avoid duplicate instances of equal value objects (there may be a better way to do this, but I can't think of any). The array simply serves to look up values by index:
private static void addToArray(Integer[] array, int key,
Integer value, Map<Integer, Integer> map) {
array[key] = map.putIfAbsent(value, value);
}
And then values can be added using:
Map<Integer, Integer> keys = new HashMap<>();
Integer[] largeArray = new Integer[1000001];
addToArray(largeArray, 1, 4, keys);
addToArray(largeArray, 2, 232, keys);
...
addToArray(largeArray, 1000000, 4, keys);
If new Integer[1000001] seems like a hack, you can still maintain a sort of "index offset" to indicate the actual key associated with index 0 in the array.
And I'd put that in a class:
class LargeMap {
private Map<Integer, Integer> keys = new HashMap<>();
private Integer[] keyArray;
public LargeMap(int size) {
this.keyArray = new Integer[size];
}
public void put(int key, Integer value) {
this.keyArray[key] = this.keys.putIfAbsent(value, value);
}
public Integer get(int key) {
return this.keyArray[key];
}
}
And:
public static void main(String[] args) {
LargeMap myMap = new LargeMap(1000_000);
myMap.put(1, 4);
myMap.put(2, 232);
myMap.put(1000_000, 4);
}
I'm not sure if you can optimize much here by grouping anything. A 'reverse' mapping might give you slightly better performance if you want to do lookup by values instead of by key (i.e. get all keys with a certain value) but since you didn't explicitly said that you want to do this I wouldn't go with that approach.
For optimization you can use an int array instead of a map, if the keys are in a fixed range. Array lookup is O(1) and primitive arrays use less memory than maps.
int offset = -1;
int[] values = new int[1000000];
values[1 + offset] = 4;
values[2 + offset] = 232;
// ...
values[1000000 + offset] = 4;
If the range doesn't start at 1 you can adapt the offset.
There are also libraries like trove4j which provide better performance and more efficient storage for this kind of data than than standard collections, though I don't know how they compare to the simple array approach.
HashMap is the worst solution. The hash of an integer is itself. I would say a TreeMap if you want an easily available solution. You could write your own specialized tree map, for example splitting the keys into two shorts and having a TreeMap within a Treemap.
This question already has answers here:
Multi-valued hashtable in Java
(13 answers)
Closed 7 years ago.
I'm looking to build a hash table where multiple String keys that share the same Byte array value are merged into one value with multiple keys. This is so the value isn't stored over and over again with different values. Adding a key with a value should also overwrite any existing key with the same name, but keep the value if it has a different key as well, but delete it when there is no other key.
EDIT: How do I build this data structure? For example, if I insert "hello" with a value, then add "World" with the same value, I would like the structure to something along the lines of [[Hello, World], Value] instead of [Hello, Value], [World, Value]. I tried using a list as my hashkey, but found I couldnt recall the value. Here is my code:
HashMap<List<String>, byte[]> map = new HashMap<List<String>, byte[]>();
public void storeByte (String id, int value) {
byte[] byteValue = new byte[value];
ArrayList<String> idlist = new ArrayList<String>();
idlist.add(id);
map.put(idlist, byteValue);
System.out.println(map);
}
public byte[] fetchByte(String id) {
ArrayList<String> idlistsearch = new ArrayList<String>();
idlistsearch.add(id);
byte[] output = map.get(id);
if(map.containsKey(idlistsearch)){
output = map.get(id);
} else {
return null;
}
return output;
I hope this makes sense,
Thank you.
i'm looking to build a hash table where multiple String keys that share the same Byte array value are merged into one value with multiple keys.
This is how HashMap and Hashtable works. There isn't any other option builtin.
When you define
byte[] bytes =
this is a reference, not an actual object. When you add this reference to the map, you are adding this reference and it can be added as many times as you like, but there is only one copy.
if I insert "hello" with a value, then add "World" with the same value,
You can do
byte[] bytes =
map.put("Hello", bytes);
map.put("World", bytes);
This is two keys and only one value.
In my class Feeds I have along with other members a member variable called "Date" which is of String type. I have an ArrayList of Feeds objects. I want to find the occurrences of objects which have the same date String. The occurrences can then be put in a HashMap that contains the String Date as key and # of occurrences as value.
Something along these lines:
List<Feeds> m_feeds = new ArrayList<Feeds>();
//add all feeds objects
m_feeds.add(...);
int occurrences = 0;
HashMap<String, Integer> repeatedDatabase = new HashMap<String, Integer>();
for (Feeds f : m_feeds){
occurrences = Collections.frequency(m_feeds, f.date);
// i know this method compares objects but i want to know how
// only a single variable can be done
repeatedDatabase.put(f.date, occurrences);
}
Other than giving you a simple solution, I took the liberty of fixing some things in your code please take a look:
List<Feeds> mFeeds = new ArrayList<>(); //If you are using Java 7+ you do not need to declare explicitly the Type in Diamonds. If you aren't, ignore this. Also fixed name to adapt to Java standards.
//add all feeds objects
m_feeds.add(...);
HashMap<String, Integer> repeatedDatabase = new HashMap<>(); //See Above.
for (Feeds f : m_feeds){
String s = f.date; //Suggestion: use a getter method, do not make public variables accessible outside class
Integer i = repeatedDatabase.get(s);
if (i == null){
repeatedDatabase.put(s, 1);
} else {
repeatedDatabase.put(s, i+1);
}
}
Your code will work if you properly overrode equals and in the Feeds class to return true for two Feeds instances having the same date (since if you try to put the same key in the Map twice, the new value will override the old value, and since in your case the values would also be the same, it would make no difference). However, each call to Collections.frequency would iterate over the entire List, which would give you an O(n^2) time complexity.
One way to make it more efficient :
for (Feeds f : m_feeds){
if (!repeatedDatabase.containsKey(f.date)) {
occurrences = Collections.frequency(m_feeds, f.date);
repeatedDatabase.put(f.date, occurrences);
}
}
This would still do more iterations than necessary. It would call Collections.frequency once for each unique date, which means you would iterate the List as many times as there are unique dates.
A more efficient implementation will not use Collection.frequency at all. Instead, you'll iterate just one time over the list and count the number of occurrences of each date yourself. This would give you an O(n) time complexity.
for (Feeds f : m_feeds){
if (!repeatedDatabase.containsKey(f.date)) {
repeatedDatabase.put(f.date, 1);
} else {
repeatedDatabase.put(f.date, repeatedDatabase.get(f.date)+1);
}
}
Why don't use directly the hashMap?
you can do something like
HashMap<String,Iteger> map = new HashMap<>();
for (Feeds f : m_feeds){
if (map.contains(f.getDate()) { // use the method to get the date
map.put(f.getDate(),map.get(f)+1);
else
map.put(f.getDate(),1);
}
I didn't test the code but it should work.
A small update to Angelo's answer..pushing it a bit further.. you can also use a map of string,int[] like this
Map<String,int[]> map = new HashMap<>();
int[] countArray = map.get(key);
if(countArray == null)
map.put(key, new int[]{0});
else
countArray[0]++;
Using the beauty of references :)
I would like to retrieve the original object of a key in a HashMap in Java, what is the best way to do it?
For example
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
Integer keyObj = new Integer(10);
Integer valueObj = new Integer(100);
// And add maybe 1 million other key value pairs here
//... later in the code, if I want to retrieve the valueObj, given the value of a key to be 10
Integer retrievedValueObj = map.get(10);
//is there a way to retrieve the original keyObj object with value 10 from map?
Basically, the user can query any value of key here just for the key object, 10 is just an example.
Some comment say, "you already have the x object, why do you want to get it?"
Well, this is the same as saying "you already have the value object, why do you want to get it?"
That is the purpose for the HashMap data structure, store and retrieval.
Retrieving a value object is easy but it seems no many people know how to retrieve the key object.
It seems like many people don't get why I want to achieve the object of 10 and ask why? why not just value 10. This is just a greatly simplified model.
Well, let me give a little bit context. The keyObj is data in another data structure and I need the exact reference of this original key object. Say, there is a linked list of all the key values, and if I want to remove a particular node in the linked list.
I am not only interested in the value "10", but also the memory location, i.e. the reference in Java of that "10" object. There could be many "10"'s in memory. But that exact object is what I want to retrieve.
The iterator approach answer below give an O(n) approach. But what I am looking for is an O(1) retrieval of the key OBJECT given the key value.
One way I can think of is to store the key object in value as well, like
class KeyAndValue {
public Integer key;
public Integer value;
public KeyAndValue(Integer key, Integer value) {
this.key = key;
this.value = value;
}
}
map<Integer, keyAndValueL> map = new map<Integer, keyAndValueL>();
Integer x = new Integer(10);
map.add(x, new KeyAndValue(x, 100));
//then I can retrieve the reference of x, given value of key 10
Integer newKeyObj = map.get(10).key;
but this approach uses more memory and looks like a hack to me. I am wondering if there is a more elegant way in Java.
A similar aproach but more generic is to store the "key + value" as an Entry instead of encapsule in another class.
Example:
Map<Integer, Entry<Integer, Integer>> map = new HashMap<Integer, Entry<Integer, Integer>>();
Integer x = new Integer(10);
map.put(x, new AbstractMap.SimpleEntry<Integer, Integer>(x, 100));
//then I can retrieve the reference of x, given value of key 10
Entry<Integer, Integer> keyObj = map.get(10);
try this
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
Integer keyObj = new Integer(10);
Integer valueObj = new Integer(100);
map.put(keyObj, valueObj);
Set<Integer> keys = map.keySet();
Iterator<Integer> iterator = keys.iterator();
while(iterator.hasNext()){
Integer x = iterator.next();
if(map.get(x) == 100)
System.out.println("key is "+ x);
}
You could store a key + value object "as the value" as you mention in your question.
What you are implementing is a variant of the flyweight pattern.
This is easiest implemented using a Map of every managed object to itself:
Map<T, T> cache = new HashMap<>();
And for every object you encounter:
T obj; // comes from somewhere
obj = cache.computeIfAbsent(obj, v -> obj); // reuse, or add to cache if not found
This has O(1) time complexity and uses only one extra object reference for each object so managed.
So what I have been trying to do is use a TreeMap I previously had and apply it to this method in which I convert it into a set and have it go through a Map Entry Loop. What I wish to do is invert my previous TreeMap into the opposite (flipped) TreeMap
'When I run my code, it gives me a comparable error. Does this mean I have to implement the comparable method? I convereted the arrayList into an Integer so I thought the comparable method would support it. Or is it just something wrong with my code
Error: Exception in thread "main" java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.lang.Comparable
Overview: Originally, my intended purpose for the program was to make a Treemap that read from a text document and specifically found all the words and the index/rows of where the words were located. Now I wish to make a "top ten" list that contains the most used words. I wanted to "flip" my treemap so that the integer values would be what would be put in order and the string would follow
public static void getTopTenWords(TreeMap<String, ArrayList<Integer>> map) {
Set<Map.Entry<String, ArrayList<Integer>>> set = map.entrySet();
TreeMap<Integer, String> temp = new TreeMap<Integer, String>();
int count = 1;
for(Map.Entry<String, ArrayList<Integer>> entry : set){
if(temp.containsKey(entry.getValue())) {
Integer val = entry.getValue().get(count);
val++;
temp.put(val, entry.getKey());
}
else {
temp.put(entry.getValue().get(count), entry.getKey());
}
count++;
}
}
Now I wish to make a "top ten" list that contains the most used words.
I wanted to "flip" my treemap so that the integer values would be what
would be put in order and the string would follow
Note that a Map contains only unique keys. So, if you try to keep your count as key, then you would need to put it in your Map by creating a new object with new Integer(count).
If you put your count in Map like: - map.put(2, "someword"), then there are chances that your previous count value gets overwritten, because Integer caches the values in range: - [-128 to 127]. So, the integer values between these range will be interned if you don't create a new object. And hence two Integer with value say 2 will point to same Integer object, and hence resulting in duplicate key.
Secondly, in your code: -
if (temp.containsKey(entry.getValue()))
using the above if statement, you are comparing an ArrayList with an Integer value. temp contains key which are integers. And values in entry are ArrayList. So, that will fail at runtime. Also, since your orginal Map contains just the location of the word found in the text file. So, just what you need to do is, get the size of arraylist for each word, and make that a key.
You would need to modify your code a little bit.
public static void getTopTenWords(TreeMap<String, ArrayList<Integer>> map) {
Set<Map.Entry<String, ArrayList<Integer>>> set = map.entrySet();
TreeMap<Integer, String> temp = new TreeMap<Integer, String>();
for(Map.Entry<String, ArrayList<Integer>> entry : set) {
int size = entry.getValue().size();
int word = entry.getKey();
temp.put(new Integer(size), word));
}
}
So, you can see that, I just used the size of the values in your entry set. And put it as a key in your TreeMap. Also using new Integer(size) is very important. It ensures that every integer reference points to a new object. Thus no duplication.
Also, note that, your TreeMap sorts your Integer value in ascending order. Your most frequent words would be somewhere at the end.