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)
Related
I'm working on my first project in JSP. I have a istance of Hashtable (hParamsRecherche) that get some values from a form.
I have to substring every element of this Hashtable :
hParamsRecherche.get("INVERSE_GEO").toString()
That contains values like:
'95','14','300','165'
I have to substring all the element that have a length bigger than 2 char, et take the first two number.
'95','14','30','16'
I think that i have to do this with a loop, but i m open to others suggestions ! Thank you !
If you want to process all strings in way that they are at most 2 digits long, you can use the following approach.
It uses streams instead of a loop, which is more elegant solution, because it uses less lines of code to solve the same problem as a loop, without sacrificing code readability.
// ... contains a list like '95','764', etc ..
// getListOfStrings() is the method, which wraps hParamsRecherche.get
var stringsToCut = getListOfString()
// The result variable now contains the list of strings, which are at most 2 digits long
var result = stringsToCut.stream
.map(s -> s.length() <= 2 ? s :s.substring(0,2))
.collect(Collectors.toList())
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.
I am using Ignite tutorial code (link below), but I want to modify it such that it operates on a different type of data and the counts are done differently - rather than incrementing counter by 1 I want to add a current value.
So let's assume I have number of occurences of a certain word in different documents, so let's assume I have something like this:
'the' 6586
'the' 925
So I want Cache to hold
'the' 7511
So given this:
try (Stream<String> lines = Files.lines(path)) {
lines.forEach(line -> {
Stream<String> words = Stream.of(line.split(" "));
List<String> tokens = words.collect(Collectors.toList());
// this is just to emphasize that I want to pass value
Long value = Long.parseLong(tokens.get(1));
stmr.addData(tokens.get(0), Long.parseLong(tokens.get(1));
I would like the value to be passed to the stmr.receiver() method, so I can add it to the val.
I have even tried creating a class variable in StreamWords that would store the value, but the value does not get updated, and in stmr.receiver() it is still 0 ( as initialized).
Link to tutorial:
Word Count Ignite Example
I managed to figure it out. In stmr.receiver(), arg is actually the value that I would like to insert, so just cast it to the object of your desire and you should be able to get the value.
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.
I've just come across some odd behaviour I wouldn't expect from an ArrayList<String> in Java. This is coming, for sure, from my poor understanding of references in Java.
Let me show you this piece of code:
List<String> myList = new ArrayList<>();
myList.add("One");
myList.add("Two");
myList.add("Two");
myList.add("Three");
for (String s : myList){
System.out.println(myList.indexOf(s));
}
This piece of code provides the following output:
0
1
1
3
How come? I've added on purpose two Strings containing the same characters ("Two"), but the object itself shouldn't be the same. What am I misunderstanding here? I was expecting this other output:
0
1
2
3
ArrayList.indexOf() doesn't use reference equality to find the object. It uses the equals() method. Notice what the documentation says (emphasis mine):
returns the lowest index i such that (o==null ? get(i)==null : o.equals(get(i))), or -1 if there is no such index.
Thus, it will match on the first string that is logically equal.
EDIT:
Andremoniy's comment is absolutely right. In the case of strings literals, because they are interned, they will also happen to have the same reference. So your 2 strings "Two" are actually the same reference in this case.
System.out.println("Two" == "Two"); // will return true because they are the same reference.
It's simply because indexOf returns the first occurrence of the item in the list that is equal to the given string. See its documentation:
Returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element. More formally, returns the lowest index i such that (o==null ? get(i)==null : o.equals(get(i))), or -1 if there is no such index.
You'll have to note two points:
most probably you are using the same String-instance, since the constant "Two" gets interned, that is all occurences of this literal will refer to the same instance.
List.indexOf() doesn't compare items by == (that is object-identity) but using equals() - that is some class-defined way to compare two objects for equality (which makes perfect sense as otherwise you wouldn't be able to find something in the list unless you already have a reference to it). So even two different String-objects (e.g. created by new String("Two")) would still produce the same output.
For completeness the quote from the javadoc of indexOf(as already mentioned in the other answers:
returns the lowest index i such that (o==null ? get(i)==null :
o.equals(get(i))), or -1 if there is no such index.
Java doesn't allow you to make a distinction between these two, but you have stumbled across the difference between (and disparity between) a method and a function.
Simply put a method may change the state of an object. A function will not. So calling your method add(String) will change the state of the List. Specifically, it adds the String to the list. indexOf(String) however is not a method, it is a function. Now sure, Java calls them methods because... that's what they call them. And it's conceivable that the implementation --could-- change the state. But we know that it doesn't, by contract.
A function, given the same inputs (of which the current state of the underlying object is part of those inputs) will always return the same result. Always. That's what's great about a function. You can call a function (a true function) as many times as you want and always get the same result as long as your inputs and the underlying data haven't changed.
Some folks at MIT did research into the analysis of functions in Java (which to avoid confusion, they call "pure methods"). It would be nice if there was a framework that allowed you to specify that a particular method was indeed a function (or as they call it, was pure) and then have an analyzer make sure you didn't accidentally introduce a mutation into code protected by that annotation.