Get matching object type from HashMap - java

First of all I'd like to say I'm fairly new into programming.
I store a few "extends" of superclass in the same HashMap.
(for example XY and XZ extends X - I store both X's, XY's and XZ's in the same HashMap).
I decided to do this for convenience - usually every time I do something, I need all of the classes that extends "X" - in this example "XY" and "XZ". Also There is no problem when I want to check whether single value is instance of specified type of object - I simply use "instanceof" formula. Let's say that I want to check if object of key "key" is instance of "XY":
X objectoftypeX = hashmap.get(key)
if(objectoftypeX instanceof XY){
//do stuff
}
But here my question comes: how to iterate only through, for instance, XY's in this HashMap?
Is this possible without checking every single object individually?
Does it make sense to do this way?
Hope you understand my problem.

Maps are fairly simple structures that optimize one form of access (a lookup by key). If you want to be able to quickly find items of a specific type, then you need to use a different structure.
For example, you could choose to make multiple maps, or making a nested map:
// Nested map, with the top level map indexing by Type (can be a String)
// and the maps inside it indexing by a String key.
Map<Type, Map<String, Object>> map = ...;
If you don't mind the overhead of checking every entry individually, you can easily get all the elements you want with a stream:
List<XY> list = hashmap.values().stream()
.filter(v -> v instanceof XY) // check type
.map(v -> (XY) v) // do cast
.collect(Collectors.toList()); // collect to list

hashmap.entrySet().filter(item -> item.value() instanceOf X).forEach(item -> ...);
It is the same, but shoter

final Object[] keySetArray = mMap.keySet().toArray();
for( int x = 0; x < keySetArray.length; x++ )
{
final Object whatStored = mMap.get( keySetArray[x] );
System.out.println("key[" + keySetArray[x] + "]: "+ whatStored );
// Make sure this check happens as it is, if you stored XY and XZ that extended X
if( whatStored instanceof of XY || whatStored instanceof XZ )
{
if( whatStored instanceof XY )
{
// Go here for instance X and XY
}
else if( whatStored instanceof XZ )
{
// Go here for instance X and XZ
}
}
}
Hope this is Close??

With standard hashmap its not possible to do this effectively (without going through everything). Purpose of hashmap is to provide fast access to elements, with only small memory overhead. Consider you have an array on integer size and a hashcode function which returns integer for each stored object. Then you will be able to find the element by applying index = hashcode(key), which is basically 1 operation to find anything. But you have a terrible memory overhead (array size is equal to all integers).
Other options would be to have a list and go through all the elements. Here you would have no memory overhead, but the search complexity would be O(n) - you would need to go through everything to be sure that the element is not in the array (or find it sooner).
Hashmap is in the middle. You allocate array of size lets say 100. Then you calculate hashcode function for the key and the result is 105. So you place the object on index {hashcode_result} modulo array_size. In our case 105 % 100 == 5.
The interesting stuff depends on implementation, what you will do, if you have a collision, which as a key2 with the same positon. For example if the hashcode value is 205, 305... (modulo will be 5 for all these hashcodes).
One possibility would be to add these additional elements to next available index 6, 7...
In java (or at least as far as I remember) the buckets are implemented as linked lists, so you will have
0 => []
1 => []
2 => []
3 => []
4 => []
5 => [k=105, k=205, k=305...]
The only way how to use hashmap for your use case would be to implement a hashcode function, which always generates the same hash for the same class. But this will degenerate the hashmap to n lists, where n is number of subclasses. And the lookup will terribly suffer (you will have to do M/n operations to lookup the value, where M is number of elements and n is the number of distinct classes), while correctly implemented hashmap (uniform distribution of hashcode values) guarantees that the number of lookups will be effectively equal to 1.
Long story short - because of the structure of hashmap, you can't do any type of data-dependent loopkup effectively (you wil kill the performance to searching through lists).
If you want to have this type of lookup, the answer of john16384 is a really good one.

Related

about java recursion to create combination of string

The question was asking me to return set containing all the possible combination of strings made up of "cc" and "ddd" for given length n.
so for example if the length given was 5 then set would include "ccddd" and "dddcc".
and length 6 would return set containing "cccccc","dddddd"
and length 7 would return set contating "ccdddcc","dddcccc","ccccddd"
and length 12 will return 12 different combination and so on
However, set returned is empty.
Can you please help?
"Please understand extremeply poor coding style"
public static Set<String> set = new HashSet<String>();
public static Set<String> generateset(int n) {
String s = strings(n,n,"");
return set; // change this
}
public static String strings(int n,int size, String s){
if(n == 3){
s = s + ("cc");
return "";}
if(n == 2){
s = s + ("ddd");
return "";}
if(s.length() == size)
set.add(s);
return strings(n-3,size,s) + strings(n-2,size,s);
}
I think you'll need to rethink your approach. This is not an easy problem, so if you're extremely new to Java (and not extremely familiar with other programming languages), you may want to try some easier problems involving sets, lists, or other collections, before you tackle something like this.
Assuming you want to try it anyway: recursive problems like this require very clear thinking about how you want to accomplish the task. I think you have a general idea, but it needs to be much clearer. Here's how I would approach the problem:
(1) You want a method that returns a list (or set) of strings of length N. Your recursive method returns a single String, and as far as I can tell, you don't have a clear definition of what the resulting string is. (Clear definitions are very important in programming, but probably even more so when solving a complex recursive problem.)
(2) The strings will either begin with "cc" or "ddd". Thus, to form your resulting list, you need to:
(2a) Find all strings of length N-2. This is where you need a recursive call to get all strings of that length. Go through all strings in that list, and add "cc" to the front of each string.
(2b) Similarly, find all strings of length N-3 with a recursive call; go through all the strings in that list, and add "ddd" to the front.
(2c) The resulting list will be all the strings from steps (2a) and (2b).
(3) You need base cases. If N is 0 or 1, the resulting list will be empty. If N==2, it will have just one string, "cc"; if N==3, it will have just one string, "ddd".
You can use a Set instead of a list if you want, since the order won't matter.
Note that it's a bad idea to use a global list or set to hold the results. When a method is calling itself recursively, and every invocation of the method touches the same list or set, you will go insane trying to get everything to work. It's much easier if you let each recursive invocation hold its own local list with the results. Edit: This needs to be clarified. Using a global (i.e. instance field that is shared by all recursive invocations) collection to hold the final results is OK. But the approach I've outlined above involves a lot of intermediate results--i.e. if you want to find all strings whose length is 8, you will also be finding strings whose length is 6, 5, 4, ...; using a global to hold all of those would be painful.
The answer to why set is returned empty is simply follow the logic. Say you execute generateset(5); which will execute strings(5,5,"");:
First iteration strings(5,5,""); : (s.length() == size) is false hence nothing added to set
Second iteration strings(2,5,""); : (n == 2) is true, hence nothing added to set
Third iteration strings(3,5,""); : (n == 3) is true, hence nothing added
to set
So set remains un changed.

Create an almost unique identifier based on a given array of numbers

Given an array of numbers, I would like to create a number identifier that represents that combination as unique as possible.
For example:
int[] inputNumbers = { 543, 134, 998 };
int identifier = createIdentifier(inputNumbers);
System.out.println( identifier );
Output:
4532464234
-The returned number must be as unique as possible
-Ordering of the elements must influence the result
-The algorithm must return always the same result from the same input array
-The algorithm must be as fast as possible to be used alot in 'for' loops
The purpose of this algorithm, is to create a small value to be stored in a DB, and to be easily comparable. It is nothing critical so it's acceptable that some arrays of numbers return the same value, but that cases must be rare.
Can you suggest a good way to accomplish this?
The standard ( Java 7 ) implementation of Arrays.hashCode(int[]) has the required properties. It is implemented thus:
2938 public static int hashCode(int a[]) {
2939 if (a == null)
2940 return 0;
2941
2942 int result = 1;
2943 for (int element : a)
2944 result = 31 * result + element;
2945
2946 return result;
2947 }
As you can see, the implementation is fast, and the result depends on the order of the elements as well as the element values.
If there is a requirement that the hash values are the same across all Java platforms, I think you can rely on that being satisfied. The javadoc says that the method will return a value that is that same as you get when calling List<Integer>.hashcode() on an equivalent list. And the formula for that hashcode is specified.
Have a look at Arrays.hashCode(int[]), it is doing exactly this.
documentation
What you're looking for is the array's hash code.
int hash = Arrays.hashCode(new int[]{1, 2, 3, 4});
See also the Java API
I also say you are looking for some kind of hash function.
I don't know how much you will rely on point 3 The algorithm must return always the same result from the same input array, but this depends on the JVM implementation.
So depending on your use case you might run into some trouble (The solution then would be to use a extern hash library).
For further information take a look at this SO question: Java, Object.hashCode() result constant across all JVMs/Systems?
EDIT
I just read you want to store the values in a DB. In that case I would recommend you to use a extern hasing library that is reliable and guaranteed to yield the same value every time it is invoked. Otherwise you would have to re-hash your whole DB every time you start your application, to have it in a consistent state.
EDIT2
Since you are using only plain ints the hash value should be the same every time. As #Stephen C showed in his answer.

How do you recursively replace occurences of a string in an array

So consider a class A with two String variables "name" and "value"
class B contains a variable which is Set of A
Set<A> allVariables
is a set that would look like this
A.name="$var1"
A.value = "x+10>2"
A.name="$var2"
A.value="11+y%10==0"
A.name="$var3"
A.value="$var1 && $var2"
What I need to do is evaluate these expressions. I'm using jexl for this. I need to iterate through the Set and replace these variable names with their respective values.
In this case, the object with name $var3 needs to be replaced with "x+10>2 && 11+y%10==0"
How do I do this?
You create 2 Hashmap, translated and toTranslate.
You parse your Set.
For each A in your Set, you look at value. If value contains any number of $element (started by $ sign), you look for this $element in your translated Hashmap keys.
If it's in there, you replace the occurrences of $element by the value found in your translated hashmap.
You do this for each different $element you found in your A object.
If all $element have been translated, you add your object A into the translated hashmap (key = name, value = value).
Else, you add it to your toTranslate hashmap.
Once all your Set has been parsed, you've got 2 hashmaps.
You create a while loop: while toTranslate hashmap is not empty, you take each value, and try to translate the $element within it by the ones in your translate hashmap.
Be careful, you may end with an infinite loop. One good thing to do would be to make sure that each time you loop on the toTranslate hashmap, the numbers of its elements is reduced. If not you're in an infinite loop.
I don't think it needs to be recursive. I think just this would work:
bool madeReplacement;
do:
bool madeReplacement = false
For each member of the set, X:
For each other member of the set, Y:
Replace all instances of Y.name with Y.value in X.value. If you replaced anything, madeReplacement = true.
while (madeReplacement)
Example:
$var1 is value 1
$var2 is value $var1
$var3 is value $var2 + 2
$var3.value contains $var2, replace $var2 with $var1 -> $var1 + 2
$var2.value contains $var1, replace $var1 with 1 -> 1
$var3.value contains $var1, replace $var1 with 1 -> 1 + 2
No value contains any other name, execution finished.
Even though we 'evaluated out of order' we eventually got the right answer anyway. However, this algorithm can be O(n^3) in the worst case (imagine if you had n variables that referenced each other in a long chain, and you started the replacement on the wrong end). One way to solve this would be to, when you X.value contains Y.name, first evaluate Y.value recursively (by doing the same loop-over-the-rest-of-the-set). This makes it O(n^2) worst case, so your suspicion that a recursive approach is appropriate may be correct ;)
(I wasn't sure if variable names were guaranteed to start with $, so I wrote it so it would not matter)

Data Structure for Storing Multi-key and Value Pairs in Java

Good evening,
I am searching for an elegant solution to implement a transition table (Specifically, for a universal pushdown automaton) that uses several discrete values for a given transition. They say a picture is worth a thousand words so here is part of my table:
State InputSymbol StackSymbol Move(NewState, Action)
------------------------------------------------------------
0 a Z0 (0, push)
0 a a (0, push)
0 a b (0, pop)
0 b Z0 (1, push)
...
Now, I have considered multi-dimensional arrays, ArrayLists of ArrayLists, and other solutions of the sort but all seem rather brutish. This is further complicated by the fact that every possible combination of my three symbols (a, b, and Z0) is not represented in the table.
I have been contemplating using a HashMap, but I am not entirely sure how to make this work with multiple key values. I was considering concatenating all three symbols together and using the resultant string as my key but that, too, seems less than elegant.
And, for the record, this is homework but actually giving an elegant solution is not strictly required. I just enjoy good code.
Thank you in advance for your assistance.
Make a class like this:
class Key{
int state;
char inputSysmbol;
String StackSymbol;
}
Then use the map Map<Key,Move>.
Make a class for Move just like above and don't forget to override hashcode and equals method in both classes.
Encapsulate {State, InputSymbol, StackSymbol} in an object. Then, use the "hashcode()" of the object as the key for your hash table. For more information regarding hash codes see Doc.
Take a look on MultiHashMap from Jakarta commons collections framework.
http://commons.apache.org/collections/api-release/org/apache/commons/collections/MultiHashMap.html
Unfortunately jakarta collection framework is not parametrized, i.e. does not support generics, so you will have to cast you your specific type.
Other solution is to implement something similar your self. Create class Move that holds your data. Create class Table that encapsulate the logic. This class may contain a list (better LinkedList) of Moves and N maps:
Map> stateIndex
Map> inputSymbolIndex
etc, etc.
implementation of add method is trivial.
Implementation of get is more interesting:
public Move get(Integer state, Character inputSymbol, StackSymbol stackSymbol) {
List<Move> stateList = stateIndex.get(state);
List<Move> inputSymbolList = stateIndex.get(inputSymbol);
List<Move> stackSymbolList = stateIndex.get(stackSymbol);
Set<Move> result = new HashSet<Move>(stateList);
result.retainAll(inputSymbolList);
result.retainAll(stackSymbolList);
if (result.size() > 1) {
throw new IllegalStateException("Unique constraint violation");
}
return result.size() == 0 ? null : result.interator().next();
}

Java: How to get n elements from a set

I was trying to find the most elegant way to get the n elements from a set starting from x. What I concluded was using streams:
Set<T> s;
Set<T> subS = s.stream().skip(x).limit(n).collect(Collectors.toSet());
Is this the best way to do it this way? Are there any drawbacks?
Similar to Steve Kuo's answer but also skipping the first x elements:
Iterables.limit(Iterables.skip(s, x), n);
Guava Iterables
Use Guava, Iterables.limit(s, 20).
Your code doesn’t work.
Set<T,C> s;
Set<T,C> subS = s.stream().skip(x).limit(n).collect(Collectors.toSet());
What is Set<T,C>? A Set contains elements of a given type so what are the two type parameters supposed to mean?
Further, if you have a Set<T>, you don’t have a defined order. “the n elements from a set starting from x” makes no sense in the context of a Set. There are some specialized Set implementations which have an order, e.g. are sorted or do retain insertion order, but since your code doesn’t declare such prerequisite but seems to be supposed to work on an arbitrary Set, it must be considered broken.
If you want to process a fraction of the Set according to an order, you have to freeze the order first:
Set<T> s;
List<T> frozenOrder=new ArrayList<>(s);
The list will have an order which will be the order of the Set, if there is any, or an arbitrary order, fixed at the creation time of the ArrayList, which will not change afterwards.
Then, extracting a fragment of it, is easy:
List<T> sub=frozenOrder.subList(x, Math.min(s.size(), x+n));
You may also convert it back to a Set, if you wish:
Set<T> subSet=new HashSet<>(sub);
That said, it’s rather unusual to process a part of a Set given by positional numbers.
The use of Stream is fine. The one drawback I can see is not all implementation of Set is ordered e.g. HashSet is not ordered but LinkedHashSet is. SO you might get different resulting set on different run.
You can just iterate over set and collect first n elements:
int n = 0;
Iterator<T> iter = set.iterator();
while (n < 8 && iter.hasNext()) {
T t = iter.next();
list.add(t);
n++;
}
The benefit is that it should be faster than more generic solutions.
The drawback is that it's more verbose than the one that you suggested.
A set - in its original manner - is not intended to have ordered elements, so you can not start from element x. SortedSet may be the "set" you want to use.
I'd convert it to a List first, like
new ArrayList(s).subList(<index of x>, <index of x + n>);
but it may have a very bad impact on performance. In this case the ArrayList would have to be stored to retrive the next subList because there is no explicit order, and the implicit order may change the next time new ArrayList(s) is called.
First, a set is not made for getting specific elements of it -
you should use a sortedSet or a ArrayList instead.
But if you have to get the elements of the set, you can use the following code
to iterate over the set:
int c = 0;
int n = 50; //Number of elements to get
Iterator<T> iter = set.iterator();
while (c<n && iter.hasNext()) {
T t = iter.next();
list.add(t);
c++;
}

Categories