Prevent treemap merging on collision - java

Edit: I should have probably mentioned that I am extremely new to Java programming. I just started with the language about two weeks ago.
I have tried looking for an answer to this questions, but so far I haven't found one so that is why I am asking it here.
I writing java code for an Dungeons and Dragons Initiative Tracker and I am using a TreeMap for its ability to sort on entry. I am still very new to java, so I don't know everything that is out there.
My problem is that when I have two of the same keys, the tree merges the values such that one of the values no longer exists. I understand this can be desirable behavior but in my case I cannot have that happen. I was hoping there would be an elegant solution to fix this behavior. So far what I have is this:
TreeMap<Integer,Character> initiativeList = new TreeMap<Integer,Character>(Collections.reverseOrder());
Character [] cHolder = new Character[3];
out.println("Thank you for using the Initiative Tracker Project.");
cHolder[0] = new Character("Fred",2);
cHolder[1] = new Character("Sam",3,23);
cHolder[2] = new Character("John",2,23);
for(int i = 0; i < cHolder.length; ++i)
{
initiativeList.put(cHolder[i].getInitValue(), cHolder[i]);
}
out.println("Initiative List: " + initiativeList);
Character is a class that I have defined that keeps track of a player's character name and initiative values.
Currently the output is this:
Initiative List: {23=John, 3=Fred}
I considered using a TreeMap with some sort of subCollection but I would also run into a similar problem. What I really need to do is just find a way to disable the merge. Thank you guys for any help you can give me.
EDIT: In Dungeons and Dragons, a character rolls a 20 sided dice and then added their initiative mod to the result to get their total initiative. Sometimes two players can get the same values. I've thought about having the key formatted like this:
Key = InitiativeValue.InitiativeMod
So for Sam his key would be 23.3 and John's would be 23.2. I understand that I would need to change the key type to float instead of int.
However, even with that two players could have the same Initiative Mod and roll the same Initiative Value. In reality this happens more than you might think. So for example,
Say both Peter and Scott join the game. They both have an initiative modifier of 2, and they both roll a 10 on the 20 sided dice. That would make both of their Initiative values 12.
When I put them into the existing map, they both need to show up even though they have the same value.
Initiative List: {23=John, 12=Peter, 12=Scott, 3=Fred}
I hope that helps to clarify what I am needing.

If I understand you correctly, you have a bunch of characters and their initiatives, and want to "invert" this structure to key by initiative ID, with the value being all characters that have that initiative. This is perfectly captured by a MultiMap data structure, of which one implementation is the Guava TreeMultimap.
There's nothing magical about this. You could achieve something similar with a
TreeMap<Initiative,List<Character>>
This is not exactly how a Guava multimap is implemented, but it's the simplest data structure that could support what you need.
If I were doing this I would write my own class that wrapped the above TreeMap and provided an add(K key, V value) method that handled the duplicate detection and list management according to your specific requirements.

You say you are "...a TreeMap for its ability to sort on entry..." - but maybe you could just use a TreeSet instead. You'll need to implement a suitable compareTo method on your Character class, that performs the comparison that you want; and I strongly recommend that you implement hashCode and equals too.
Then, when you iterate through the TreeSet, you'll get the Character objects in the appropriate order. Note that Map classes are intended for lookup purposes, not for ordering.

Related

Check if part of a String exists in HashMap

I have a HashMap of 60k key/value pairs.
I have 100 strings and out of those 100 strings one has a substring which exists in HashMap.
I would have to repeat this process thousand times. Is there is an efficient approach to do this?
Let's say, the hash contains like:
journal of america, rev su arabia, comutational journal, etc..
And the strings like:
published in rev su arabia
the publication event happened in
computationl journal 230:34
The first and third string contains the key/value in the hash and I need to find out those.
Code (not efficient)
private String contains(String candidateLine)
{
Iterator<String> it = journalName.iterator();
while (it.hasNext())
{
String journalName = it.next();
if (candidateLine.contains(journalName))
return journalName;
}
return null;
}
Please suggest.
Given your requirements, the only answer is: wrong design point. You are basically asking how to efficiently support "full text" search capabilities. And for that problem, the answer is: don't do it yourself.
Meaning: forget about re-inventing the wheel here. Instead, pick up an existing solution, such as Lucene (library) or products such as Solr or ElasticSearch ( see here for more information).
You see, most likely we are looking at a "real world" production problem here. So even when you find a clever way to build your own data structure to support your current requirements, chances are high that sooner or later "more" requirements will be coming your way.
Therefore I seriously suggest that clarify the exact problem to solve, and then identify that existing product that best solves the problem. Otherwise you will be fighting uphill battles like forever.

proper mathematics way to explain in a comment that there is no duplicate items in a set

i'm writing some code, and I want my code to be well documented.
there is a part in the code where I'm checking that when there is a try to insert new element E to a list L, the element E will be unique (so there is no other elements in L that equals to him).
I'm having difficult to write a user-friendly mathematics comment, something that will look like the example bellow
the function will change all elements (that in list L) fields E.color to "Black" only if color to black element.size > 10.
so in that case I will write the comment -
[ X.color="Black" | X in L, X.size > 10]
but for the scenario above I couldnt find any satisfied mathmatics comment.
A mathematical set by definition has no duplicates inside it, so perhaps using the a set rather than a list would solve your problem.
However if that's too hard to change now then you could write something like:
[ L.insert(E) | E not in L ]
where E is the element and L is the list.
an exhaustive answer to your question requires two observations:
Best coding practices require you to know collections very well and when to use them. So you want the right collection for the right Job. In this case as advised in other comments, you need to use a Set instead of a list. A Set uses a Map under the hood, having your elements as keys and values as DEFAULT. Every time that you add an element to your Set, the Hash value for it is calculated and compared using equals to the existing elements. So no dups are allowed.
I really appreciate the fact that you want to write good comments, however you don't need to for the following reasons:
List and Sets behaviour is largely documented already, so nobody expects you to comment them;
Books like Refactoring and Clean code, teach us that good code should never be commented as it should be self explaining. That means that your method/class/variable name should tell me what the method is doing.

ArrayList Sorting Based on Method

I am in need of some help trying to compare 2 arraylist and then sorting; If I am even on the right track. So here is my problem..
Say arraylist 1 contains the objects in which 3 integers adds up to 4 and each integer has to be at least greater or greater/equal to the next number.
So for example, arraylist 1 contains {(2,1,1), (2,2,0), (3,1,0), (4,0,0)}.
Also each object integers are sorted from greatest to least.
Now I have a take the (2,1,1) and send it to a method to perform an algorithm on it. for each integer place, i need to add 2 to that integer place, and subtract 1 from the rest. We can call these A event, B event, or C Event.
for example, (2,1,1) which these events would be
A Event: (4,0,0)
B Event: (3,1,0)
C Event: (3,1,0)
Now, my question is because A event produced (4,0,0) how would I sort the first arraylist to have that number come next and then have (3,1,0) but without (3,1,0) duplicating. So after sorting the array, it should be
(2,1,1) ( 4,0,0) (3,1,0) (2,2,0)
At present your question is not clear to me, but I think I can help point you in the right direction.
Since you said:
without (3,1,0) duplicating
I'd suggest that to ensure uniqueness of objects in a Collection you should consider using a class that implements the Set interface (see Javadoc for Set for details).
Assuming you are not writing the sorting algorithm yourself you could use a SortedSet and then implement the necessary functionality (Comparable interface or Comparator) so that your objects are sorted in the way you want (the earlier link provides links that describe how to do this).
Hope this helps, and if you could try to make the question more clear I'd be happy to offer some additional pointers.
Here are some of the confusing parts that you could work on:
each integer has to be at least greater or greater/equal to the next number.
This is confusing because you're giving two conflicting requirements. Is each number strictly greater than the next or is it greater than or equal to the next?
Also each object integers are sorted from greatest to least.
I'm not sure what you mean by this because you already said that the integers contained in the objects were in a specific order.
because A event produced (4,0,0) how would I sort the first arraylist to have that number come next
You're not really telling us how the sorting should work. Can you describe the algorithm more - how does it decide the order of the items, how should one item be compared with another?

Best pratice for using array as the key of memoization in Java

I am doing some algorithm problems in Java, and from time to time the problem needs memoization to optimize speed. And often times, the key is an array. What I usually uses is
HashMap<ArrayList<Integer>, Integer> mem;
The main reason here to use ArrayList<Integer> instead of int[] is that the hashCode() of an primitive array is calculated based on the reference, but for ArrayList<Integer> the value of the actual array is compared, which is desired behavior.
However, it is not very efficient and code can be pretty lengthy as well. So I am wondering if there is any best practice for this kind of memoization in Java? Thanks.
UPDATE: As many have pointed this out in the comments: it is a very bad idea to use mutable objects as the key of a HashMap, which I totally agree.
And I am going to clarify the question a little bit more: when I use this type of memoization, I will NOT change the ArrayList<Integer> once it is inserted to the map. Normally the array represents some status, and I need to cache the corresponding value for that status in case it is visited again.
So please do not focus on how bad it is to use a mutable object as the key to a HashMap. Do suggest some better way to do this kind of memoization please.
UPDATE2: So at last I choose the Arrays.toString() approach since I am doing algorithm problems on TopCoder/Codeforces, and it is just dirty and fast to code.
However, I do think HashMap is the more reasonable and readable way to do this.
You can create a new class - Key, put an array with some numbers as a field and implement your own hascode() based on the contents of the array.
It will improve the readability as well:
HashMap<Key, Integer> mem;
If your ArrayList contains usually 3-4 elements,
I would not worry much about performance. Your approach is OK.
But as others pointed out, your key is thus mutable which is
a bad idea.
Another approach is to append all elements of the ArrayList
together using some separator (say #) and thus have this kind
of string for key: 123#555#66678 instead of an ArrayList of
these 3 integers. You can just call Arrays.toString(int[])
and get a decent string key out of an array of integers.
I would choose the second approach.
If the input array is large, the main problem seems to be the efficiency of lookup. On the other hand, your computation is probably much more expensive than that, so you've got same CPU cycles to spare.
Lookup time will depend both on the hashcode calculation and on the brute-force equals needed to pinpoint the key in a hash bucket. This is why the array as a key is out of the question.
The suggestion already given by user:XpressOneUp, creating a class which wraps the array and provides its custom hash code, seems like your best bet and you can optimize hashcode calculation to involve only some array elements. You'll know best which elements are the most salient.
If the values in the array are small integer than here is way to do it efficiently :-
HashMap<String,Integer> Map
public String encode(ArrayList arr) {
String key = "";
for(int i=0;i<arr.size();i++) {
key = key + arr.get(i) + ",";
}
return(key);
}
Use the encode method to convert your array to unique string use to add and lookup the values in HashMap

Java - Recover the original order of a list after its elements had been randomized

The Title is self explanatory. This was an interview question. In java, List is an interface. So it should be initialized by some collection.
I feel that this is a tricky question to confuse. Am I correct or not? How to answer this question?
Assuming you don't have a copy of the original List, and the randomizing algorithm is truly random, then no, you cannot restore the original List.
The explanation is far more important on this type of question than the answer. To be able to explain it fully, you need to describe it using the mathematical definitions of Function and Map (not the Java class definitions).
A Function is a Map of Elements in one Domain to another Domain. In our example, the first domain is the "order" in the first list, and the second domain is the "order" in the second list. Any way that can get from the first domain to the second domain, where each element in the first domain only goes to one of the elements in the second domain is a Function.
What they want is to know if there is an Inverse Function, or a corresponding function that can "back map" the elements from the second domain to the elements in the first domain. Some functions (squaring a number, or F(x) = x*x ) cannot be reversed because one element in the second domain might map back to multiple (or none) elements in the first domain. In the squaring a number example
F(x) = x * x
F(3) = 9 or ( 3 -> 9)
F(12) = 144 or ( 12 -> 144)
F(-11) = 121 or (-11 -> 121)
F(-3) = 9 or ( -3 -> 9)
attempting the inverse function, we need a function where
9 maps to 3
144 maps to 12
121 maps to -11
9 maps to -3
Since 9 must map to 3 and -3, and a Map must have only one destination for every origin, constructing an inverse function of x*x is not possible; that's why mathematicians fudge with the square root operator and say (plus or minus).
Going back to our randomized list. If you know that the map is truly random, then you know that the output value is truly independent of the input value. Thus if you attempted to create the inverse function, you would run into the delimma. Knowledge that the function is random tells you that the input cannot be calculated from the output, so even though you "know" the function, you cannot make any assumptions about the input even if you have the output.
Unless, it is pseudo-random (just appears to be random) and you can gather enough information to reverse the now-not-truly random function.
If you have not kept some external order information (this includes things like JVM trickery with ghost copies), and the items are not implicitly ordered, you cannot recover the original ordering.
When information is lost, it is lost. If the structure of the list is the only place recording the order you want, and you disturb that order, it's gone for good.
There's a user's view, and there's internals. There's the question as understood and the question as can be interpreted.
The user's view is that list items are blocks of memory, and that the pointer to the next item is a set of (4?8? they keep changing the numbers:) bytes inside this memory. So when the list is randomized and the pointer to the next item is changed, that area of memory is overriden and can't be recovered.
The question as understood is that you are given a list after it had been randomized.
Internals - I'm not a Java or an OS guy, but you should look into situations where the manner in which the process is executed differs from the naive view: Maybe Java randomizes lists by copying all the cells, so the old list is still kept in memory somewhere? Maybe it keeps backup values of pointers? Maybe the pointers are kept at an external table, separate from the list, and can be reconstructed? Maybe. Internals.
Understanding - Who says you haven't got an access to the list before it was randomized? You could have just printed it out! Or maybe you have a trace of the execution? Or who said you're using Java's built it list? Maybe you are using your own version controlled list? Or maybe you're using your own reversable-randomize method?
Edwin Buck's answer is great but it all depends what the interviewer was looking for.

Categories