which is the best way to write a bidimensional hashmap efficiently in Java? Just to give an example of what I'm talking about: I'm developing some algorithms related to collective intelligence, these algorithms works by calculating correlation between pairs of elements..
Without caching these values, since they are calculated on same pairs multiple times, performance are horrible.. (algorithms can be O(n^2) but maybe O(n^3) so I was thinking about using an HashMap to store values to be used multiple times.
Which is the most efficient way to implement such a data structure in Java? It should be possble to cache and remove a value generated by a pair of elements with O(1), but using an explicit class seems too heavy anyway.
If Java will turn out to be not enough I'll have to switch to C/C++, so any idea related to these languages are welcome too.
Thanks
The easiest way to do this is to define a Pair class. It should be immutable (hash keys should not change), and hashCode() should be consistent with equals.
Something like (method implementations omitted):
public class Pair() {
int a, b;
public Pair(int a, int b);
public int getA();
public int getB();
public boolean equals(Object obj);
public int hashCode();
}
Notes:
If you don't want ints, sub in whatever type you want, or make your Pair class generic if you want it to be flexible.
It would be up to you whether (x, y) == (y,x).
With this in hand, you can have a HashMap<Pair, SomethingElse> as your cache.
I partially solved the problem by concatenating hashcodes of both items using something like this:
private long computeKey(Object o1, Object o2)
{
int h1 = o1.hashCode();
int h2 = o2.hashCode();
if (h1 < h2)
{
int swap = h1;
h1 = h2;
h2 = swap;
}
return ((long)h1) << 32 | h2;
}
I still have to figure out which is the most efficient way to store all the elements already cached with a specified one to remove them when the algorithm don't need the item anymore, just to avoid filling of the HashMap with a waste of item. That's because the kind of algorithm merges two items at every iteration removing them from used ones but adding the new generated item.
Google Collections supports bi-directional hashmaps, see BiMap.
(BTW, Google Collections seems to be gaining more mindshare over Apache Collections.)
Update: Note #danben and #sateesh's clarification. A BiMap would be fine if you need to get a y given an x, or an x given a y. But it sounds like you really want to look up an (x, y) point and get back a value that contains your cached information. In that case, go with #danben's suggestion.
Related
I am building a simple 2D game in Java, but I cannot decide how to store the map data. I want something like arrays, however global arrays in Java are static, and they cannot be dynamic sized. I am going to load the map from a file, however, sometimes the maps are differently sized.
Hashmap looks too complicated for what I want. What would be a good way to store the data easily? I want to create a simple method to retrieve the data for each coordinate.
Example:
int blockdata = blockCheck(5, 8);
It would then return the data "5a7" or whatever the data is. In similar games I have just had static variables in an array, but I do not know how to do this being dynamically sized.
Generally I would recommend creating a custom Map class, that encapsulates the storage in private members. That way, if you change the internal storage, the rest of your code can still work unchanged. You can give the Map a nice APi so you can do stuff like map.get(10,12) and map.set(3,4,BRICK_WALL); etc.
For the internal storage you have a few choices / techniques to choose between:
Use nested data structures: an ArrayList of ArrayListss is fine to represent a 2D map, and allows for dynamic resizing
Use an existing lower-level library that provides 2D Map storage
Use nested arrays like Tile[][] or similar. If you want to create a new map, you'll need to create a new nested array of course, but this is generally not a problem.
Use a flat array Tile[] or similar, and compute index locations into this array. You can compute unique indexes with something like array[x + y * columnCount].
Personally, I'd probably go for arrays. They are the most lightweight and efficient, and I think dynamic sizing is generally unnecessary: if you need maps of different sizes just create a new Map of the required size each time.
I want something like arrays, however global arrays in Java are static, and they cannot be dynamic sized. I am going to load the map from a file, however, sometimes the maps are differently sized.
You can add a class member and initialize it with dynamic value in the constructor i.e. when you create it's object
class Map {
int[][] twodspace;
Map(){}
Map(int len, int width){
twodspace = new int[len][width];
}
}
You could have an ArrayList of ArrayLists. For example:
ArrayList<ArrayList<Integer>> myarray= new ArrayList<>();
int blockCheck(int x, int y) {
return myarray.get(x).get(y);
}
I am using a data structure based on tree maps, mainly because it's relatively sparse in my case and I need to be able to iterate in order:
public class Grid<T> implements Iterable<T> {
private TreeMap<Integer,TreeMap<Integer,T>> data = new TreeMap<Integer,TreeMap<Integer,T>>();
public T get(int row, int col) {
TreeMap<Integer,T> r = data.get(row);
return r == null ? null : r.get(col);
}
public void set(int row, int col, T value) {
TreeMap<Integer,T> r = data.get(row);
if (r == null) {
r = new TreeMap<Integer, T>();
data.put(row, r);
}
r.put(col, value);
}
}
I'd recommend to have a similar level of abstraction (your own 2d "Grid" backed by whatever data structure that suits your needs best), so you can easily tweak the underlying implementation (array, tree, hasmap, whatever) based on your needs without having to change the rest of the application code.
I just used a txt file with structure like this:
*
* + +
* ____
*
**************************
And then I was just processing the file. Simplest way there was for me. Then for example + character is something, - is something etc.
Well , I'm stock on something very simple but I can't figure it out.
First off, I know that there is Collection.sort() method, but my ArrayList is sort of links to data to main object, and my sorting is needed to be made according to this object's data.
Like this is a sport competition and ArrayList<Integer> numbers is keeping numbers of participants that has passed a checkpoint.
And I need to sort this ArrayList by the best time from min to max to set them on who's on 1st place, 2nd etc.
for this I should ask my Competiton object :
public ArrayList<Integer> sort (ArrayList<Integer> numbers)
for (int i=0;i<numbers.size){
long time = competition.participant.get(numbers.get(i)).getTimeOfLastCheckPoint();
/*Do something to make another ArrayList<Integer> sortedArray
where all this will be sorted by this time parameter from minimal to maximum*/
return sortedArray;
}
this is not the actual code, but you've got the idea. I stuck with trying to find seemingly easy solution.
Please Help
It seems awkward to sort an ArrayList<Integer> based on other things that have nothing directly to do with what you actually want to sort on -- the times.
I would design it differently. It looks you have some kind of object defined on which you can call getTimeOfLastCheckPoint(). For now, I'm assuming it's called Participant. Instead of maintaining an ArrayList<Integer> to store index-based references to your participants, I would maintain an ArrayList<Participant>.
Then I would create a class that implements Comparator<Participant> (perhaps ParticipantComparator) (Comparator javadocs) that knows how to compare Participants based on the results of the call to getTimeOfLastCheckPoint(). Then sorting is simply Collections.sort(participantsArrayList, new ParticipantComparator());.
Write a java.util.Comparator that compares Integers by using them as index in your participants-array:
public class ParticipantIndexComparator implements Comparator<Integer> {
final List<Participant> participants;
public ParticipantIndexComparator(List<Participant> participants) {
this.participants = participants;
}
#Override
public int compare(Integer i1, Integer i2) {
long l1 = participants.get(i1).getTimeOfLastCheckPoint();
long l2 = participants.get(i2).getTimeOfLastCheckPoint();
return Long.compare(l1, l2);
}
}
Now you can use this comparator to sort your integers:
Collections.sort(numbers, new ParticipantIndexComparator(participants));
But before doing so, ask yourself why your list contains Integer-objects that are indices to the participants-list, instead of the Participants themselves!
For me, this sounds like a workaround solution for a half-done SQL query. In case that your data resides in a data base (and I'm pretty sure that this is the case), modify your SQL- query so that you don't have to do that sorting of data at application level. This is good for at least two reasons:
Simplyfiy application logic
Speed up execution (The data base can do such sorting much faster)
You can use a Comparator to sort the list according to their race duration and also use for-each loop in Java.
Imagine a simple case:
class B{
public final String text;
public B(String text){
this.text = text;
}
}
class A {
private List<B> bs = new ArrayList<B>;
public B getB(String text){
for(B b :bs){
if(b.text.equals(text)){
return b;
}
}
return null;
}
[getter/setter]
}
Imagine that for each instance of A, the List<B> is large and we need to call getB(String) often. However assume that it is also possible for the list to change (add/remove element, or even being reassigned).
At this stage, the average complexity for getB(String) is O(n). In order to improved that I was wondering if we could use some clever caching.
Imagine we cache the List<B> in a Map<String, B> where the key is B.text. That would improve the performance but it won't work if the list is changed (new element or deleted element) or reassigned (A.bs points to a new reference).
To go around that I thought that, along with the Map<String, B>, we could store a hash of the list bs. When we call getB(String) method, we compute the hash of the list bs. If the hash hasn't changed, we fetch the result from the map, if it has we reload the map.
The problem is that computing the hash for a java.util.List goes through all the element of the list and computes their hash, which is at least O(n).
Question
What I'd like to know is whether the JVM will be faster at computing the hash for the List than going through my loop in the getB(String) method. May be that depends on the implementation of hash for B. If so what kind of things could work? In a nutshell, I'd like to know whether this is stupid or could bring some performance improvement.
Without actually explaining why, you seem for some reason to believe that it is essential to keep the list structure as well. The only reasonable reason for this is that you need the order of the collection to be kept consistent. If you switch to a "plain" map, the order of the values is no longer constant, e.g. kept in the order in which you add the items to the map.
If you need both to keep the order (list behaviour) and access individual items using a key, you can use a LinkedHashMap, which essentially joins the behaviour of a LinkedList and a HashMap. Even if LinkedHashMap.values() returns a collection and not a list, the list behaviour is guaranteed within the collection.
Another issue with your question is, that you cannot use the list's hash code to safely determine changes. If the hash code has changed, you are indeed sure that the list has changed as well. If two hash codes are identical, you can still not be sure that the lists are actually identical. E.g. if the hash code implementation is based on strings, the hash codes for "1a" and "2B" are identical.
If so what kind of things could work?
Simply put: don't let anything else mutate your list without you knowing about it. I suspect you currently have something like:
public List<String> getAllBs() {
return bs;
}
... and a similar setter. If you stop doing that, and instead just have appropriate mutation methods, then you can make sure that your code is the only code to mutate the list... which means you can either remember that your map is "dirty" or just mutate the map at the same time that you mutate the list.
You could implement your own class IndexedBArrayList which extends ArrayList<B>.
Then you add this functionality to it:
A private HashMap<String, B> index
All mutator methods of ArrayList are overridden to keep this index hash map updated in addition to calling the corresponding super-method.
A new public B getByString(String) method which uses the hash map
From your description it does not seem that you need a List<B>.
Replace the List with a HashMap. If you need to search for Bs the best data structure is the hashmap and not the list.
I had to write a merge sort function in Java. No problem. Well, a little, but I got through it. Then the follow up question I didn't get.
Question: Given an array A[][] such that A[i][0] is a float and A[i][1] is a nonnegative int giving the multiplicity of the value A[i][0] (here think of a big vector that's been collapsed down by combining repeated entries and recording how many got combined), write a version of merge sort that returns B[][] where B[i][0] < B[i+1][0] for all i.
Any ideas? The best I could do was merge sort and then group the equal ones, but apparently you can do it all in one step.
Strage question... and using different types in these arrays is just ugly (personal point of view).
However, the most useful thing to do, is to rewrite your merge function with a Comparator.
This way you can sort using whatever property you want.
You would end up with a signature like void merge(A[] arr, Comparator<? super A> comp).
By the way, the Java implementation of sort is a lot like this.
To solve your question you would call:
A[][] a = ...;
merge(a, new Comparator<A[]>() {
int compare(A[] a, A[] b) {
return ((Float)a[0]) - ((Float)b[0]);
}
});
how can I create an array of tuples in jsp (java)
like
(a:1, b:2)
(c:3, d:4)
...
...
Create a tuple class, something like:
class Tuple {
private Object[] data;
public Tuple (Object.. members) { this.data = members; }
public void get(int index) { return data[index]; }
public int getSize() { ... }
}
Then just create an array of Tuple instances.
if you want an arbitrary size tuple, perl hash style, use a Map<K,V> (if you have a fixed type of keys values - your example looks like Map<Character,Integer> would work - otherwise use the raw type). Look up the java collections for more details about the various implementations.
Given those tuples, if you want to stick them in an sequential collection, I'd use a List (again, look up the collections library).
So you end up with
List<Map<K,V>> listOfTuples
if you need something more specific (like, you'll always have x1, x2, x3 in your tuple) consider making the maps be EnumMaps - you can restrict what keys you have, and if you specify a default (or some other constraint during creation) guarantee that something will come out.
There's no default pair / n-tuple class in Java; you'd have to roll your own.
you could use the HashSet class.
If you are dealing with tuples of fixed size, with fixed names of the attributes, define a simple data class of your own, and then define the array of this class.
If on the other hand you want the attribute names to be flexible and determined at runtime, use a Map structure. In your example above, it seems like HashMap<String,Integer> can do the job. You may want to wrap it in order to reduce its functionality, and maybe also add more specific functionality.
I know I am late to the party but an array of points should do the job.
Check here to see the documentation about points.