I'm trying to use memoization pattern in my recursive operation, but something is going wrong.
Below is my method.
private Map<String, MyDTO> map = new ConcurrentHashMap<>();
private void searchRecursive(String uuid) {
if (!map.containsKey(uuid)) {
MyDTO obj = myClient.getMyObject(uuid);
if("one".equals(obj.getType()) || "two".equals(obj.getType())){
if(Objects.nonNull(obj.getChildren())){
obj.getChildren().forEach(child -> searchRecursive(child.getId()));
}
} else if("three".equals(obj.getType())) {
map.put(uuid, obj);
}
}
}
I would like to improve the performance of this operation!
Thank you very much for the help!
I think as #John3136 said, getType(), getChildren() called more than one time, better to create a reference and reduce call time for those methods.
I'm guessing the obj you are trying to search is like a graph or tree, so I think you can try to convert to iterate the child use the BFS method (Queue like data structure), that would be better.
Related
Eg; I want my TreeSet / HashMap to store 1,19,3,4,2,0 in that order since it is the order they are added to the map.
I hear that LinkedHashMap is the go-to solution. But my question is, can we produce the same result with TreeSet/HashMap, with some modification introduced to comparedTo()?
No. You cannot do that. You must use LinkedHashMap or another custom map implementation; TreeMap and HashMap cannot support insertion order.
You could do it with a very very complicated compareTo(...) method, but it would involve basically keeping track of the state of the tree yourself, manually, somewhere external to the tree. That's just re-creating a LinkedHashMap without using a LinkedHashMap. Same thing, but much more complex and hard to read and maintain code. No reason to do that.
"You cannot do that." Well, you can. All you need to do is add the insertion order to the object you're storing and account for it in the compareTo or comparator.
#Override
public int compareTo(Object o) {
int returnValue = 0;
if(o instanceof InsertionObject) {
InsertionObject newObject = (InsertionObject)o;
if(this.insertionOrder != newObject.insertionOrder) {
if(this.insertionOrder < newObject.insertionOrder) {
returnValue = -1;
}
else {
returnValue = 1;
}
}
}
else {
throw new RuntimeException("Insert error message here.");
}
return returnValue;
}
I'm not saying you should, but you could. This smells like an interview question or a homework problem, so they probably are just testing to see if the poster understands what is going on inside the underlying collections?
This might sound like a dumb question, because it might be no other way to do this. After designing my own list, this sort of "issue" came up in multiple occasions. To clarify, I have a problem with returning a cached variable after assigning new value to the original variable. Here's an example:
public T next() {
final Node<T> thisNode = posNode;
posNode = posNode.getNext();
return thisNode.getData();
}
This might seem like a non-issue, but occasionally multiple variables has to be cached before returning a valid value. I do not really like it, because personally I think it reduces the code's readability, especially when caching multiple variables.
Is there another way to write this code while maintaining its functionality? Basically a way to assign a new value to a variable after the return statement:
public T next() {
return posNode.getData();
posNode = posNode.getNext();
}
Thanks! :)
The second way is not possible as the code is not reachable after return. And your first way is the best way far you to achieve what you are looking for and it is not code smell. Often they refer as temp variables. Use them and better convey a message to the code reader by better naming convention. For ex tempPosNode
An elegant (but with some cognitive dissonance) option is a dummy method.
public static <T> T first(T first, Object... theRest) {
return first;
}
public T next() {
return first(posNode.getData(), posNode = posNode.getNext());
}
You can use a finally block to execute it, but it will execute even after exceptions:
public T next() {
try {
return posNode.getData();
} finally {
posNode = posNode.getNext();
}
}
Having this code:
public Map<Job, Collection<JobTransform>> getPartitioning() {
Map<Job, Collection<JobTransform>> partitioning = new IdentityHashMap<>();
for (JobTransform jobTransform : content) {
Job job = jobTransform.getJob();
Collection<JobTransform> collection = partitioning.get(job);
if (collection == null) {
collection = new LinkedList<>();
partitioning.put(job, collection);
}
collection.add(jobTransform);
}
return partitioning;
}
and 'content' being a constructor parameter for the class this method is implemented in, how can I convert the for-each loop into code using Stream API in Java? For now I have only
content.stream().map(JobTransform::getJob)
and I don't know how can I use each job further. Do I use the API wrong? Please help me to improve my code!
content.stream().collect(Collectors.groupingBy(JobTransform::getJob, IdentityHashMap::new, Collectors.toCollection(LinkedList::new)));
This will do exactly the same thing as your non-stream code.
Is there a way to return some value from within a for loop without jumping out of the loop?
I am implementing a static analysis tool where I have to analyze a list of methods (CFGs) in a for loop. The size of CFG list is not known in advance. Each method in the for loop has to return some value. As asked above, is there a way to do it in a loop without breaking the loop? One possible alternative comes in mind is that I can unroll the loop, assuming the maximum list size could be some fixed value. But this does not solve the problem completely. Any help would be appreciated.
code looks like below.
for(CFG cfg: cfgList)
{
val = analyze(cfg);
return val; //I want for loop not to stop here.
}
P.S. I cannot store the values in a list to return values later.
Edit1:
For example, consider following statements.
call method1();
st2;
st3;
...
This method1() can be any of five different methods. For all five possible options, I want to analyze each of them, return their values and analyze rest of the statements accordingly. So, I would analyze these 5 methods as below.
call method1-option1();
st2;
st3;
...
call method1-option2();
st2;
st3;
...
call method1-option3();
st2;
st3;
...
Hope, it helps in understanding the question.
No you can not return value from loop without jumping out of it. According to your need you have to save value in other list and you can return that list after finishing the loop.
In Java 8, you can do:
Iterator<AnalysisResult> lazyAnalysisResults = cfgList.stream()
.map(cfg -> analyze(cfg))
.iterator();
And then the Iterator will supply new analyzed results one at a time, without you needing to collect them all into a list first.
Prior to Java 8, if you want your transformation to be lazy, the best you can do is to implement an Iterator yourself:
public final class AnalyzingIterator extends Iterator<AnalysisResult> {
private final Iterator<CFG> iter;
public AnalyzingIterator(Iterator<CFG> iter) {
this.iter = iter;
}
#Override public boolean hasNext() {
return iter.hasNext();
}
#Override public AnalysisResult next() {
return analyze(iter.next());
}
#Override public boolean remove() {
throw new UnsupportedOperationException();
}
}
If you don't want to store results in a List and return it all together you can use callback mechanism.
Use analyze() to start a new thread passing cfg as well as reference to this. When processing is over make that processing thread call a callback method on your current instance / thread passing the analyzed value. Continue to do whatever you intend to do with this returned value in the callback method. And you don't have to alter your for loop.
In my code I have a List<Person>. Attributes to the objects in this list may include something along the lines of:
ID
First Name
Last Name
In a part of my application, I will be allowing the user to search for a specific person by using any combination of those three values. At the moment, I have a switch statement simply checking which fields are filled out, and calling the method designated for that combination of values.
i.e.:
switch typeOfSearch
if 0, lookById()
if 1, lookByIdAndName()
if 2, lookByFirstName()
and so on. There are actually 7 different types.
This makes me have one method for each statement. Is this a 'good' way to do this? Is there a way that I should use a parameter or some sort of 'filter'? It may not make a difference, but I'm coding this in Java.
You can do something more elgant with maps and interfaces. Try this for example,
interface LookUp{
lookUpBy(HttpRequest req);
}
Map<Integer, LookUp> map = new HashMap<Integer, LookUp>();
map.put(0, new LookUpById());
map.put(1, new LookUpByIdAndName());
...
in your controller then you can do
int type = Integer.parseInt(request.getParameter(type));
Person person = map.get(type).lookUpBy(request);
This way you can quickly look up the method with a map. Of course you can also use a long switch but I feel this is more manageable.
If good means "the language does it for me", no.
If good means 'readable', I would define in Person a method match() that returns true if the object matches your search criteria. Also, probably is a good way to create a method Criteria where you can encapsulate the criteria of search (which fields are you looking for and which value) and pass it to match(Criteria criteria).
This way of doing quickly becomes unmanageable, since the number of combinations quickly becomes huge.
Create a PersonFilter class having all the possible query parameters, and visit each person of the list :
private class PersonFilter {
private String id;
private String firstName;
private String lastName;
// constructor omitted
public boolean accept(Person p) {
if (this.id != null && !this.id.equals(p.getId()) {
return false;
}
if (this.firstName != null && !this.firstName.equals(p.getFirstName()) {
return false;
}
if (this.lastName != null && !this.lastName.equals(p.getLastName()) {
return false;
}
return true;
}
}
The filtering is now implemented by
public List<Person> filter(List<Person> list, PersonFilter filter) {
List<Person> result = new ArrayList<Person>();
for (Person p : list) {
if (filter.accept(p) {
result.add(p);
}
}
return result;
}
At some point you should take a look at something like Lucene which will give you the best scalability, manageability and performance for this type of searching. Not knowing the amount of data your dealing with I only recommend this for a longer term solution with a larger set of objects to search with. It's an amazing tool!