How to improve a join between two Json results? - java

I am attempting to merge two API results which both return JSON into a single list of objects.
Currently, I'm basically iterating through two for loops, to match up the entries in each list. Is there a more efficient way of doing this? The process is currently taking much too long for my liking.
I have the following code:
private List<SingularEntry> combineAdsAndCreatives(JsonNode creativeEntries, JsonNode adEntries)
{
List<SingularEntry> entries = new ArrayList<SingularEntry>();
for (JsonNode node : adEntries) {
node = adHashToNode(node, creativeEntries);
if(node != null)
{
entries.add(convertNode(node));
}
}
return entries;
}
private JsonNode adHashToNode(JsonNode node, JsonNode creativeEntries)
{
for(JsonNode creativeNode : creativeEntries)
{
if( node.get("campaign_network_id").toString().equals(creativeNode.get("campaign_network_id").toString()) && node.get("ad_network").toString().equals(creativeNode.get("ad_network").toString()) )
{
ObjectNode newNode = (ObjectNode) node;
newNode.put("image_hash", creativeNode.get("image_hash"));
newNode.put("creative_name", creativeNode.get("creative_name"));
return newNode;
}
}
return null;
}

It's better to define a JsonNodeWrapper class which keeps the JsonNode and define equals() method (also you may need hashCode() method) to compare the wrapper with another JsonNode wrapper.
The go through both lists creating the JsonNodeWrappers and place all the created ones into a Set to leave unique ones only.

Related

How to merge two descending singly linkedlist into one ascending linkedlist using Recursion without any helper method?

I can merge the two descending singly linkedlists into one descending list with just one recursion, but I don't know how to do to make the result ascending instead without creating any helper methods.
This is my code for merging them into descending order. I was trying to modify within this code to make it ascending but failed. Please help me out~
public Node mergeByRecursion(Node node1, Node node2) {
if (node1 == null) {
return node2;
} else if (node2 == null) {
return node1;
}
if (node1.value < node2.value) {
node1.next = merge(node1.next, node2);
return node1;
} else {
node2.next = merge(node1, node2.next);
return node2;
}
}
Here is a picture of the detailed question that I am trying to solve.
UPDATE
I have figured out a solution that works, but not sure if it is the best solution and fits the requirement 100% so I made another post for asking a code review. In case, anyone also gets stuck by this question wanna know a potential solution.
Code Review
I guess maybe this would work:
public Node mergeByRecursion(Node node1, Node node2) {
if (node1 == null) {
return node2;
}
if (node2 == null) {
return node1;
}
if (node1.getElement().value < node2.getElement().value) {
node1.getNext() = mergeByRecursion(node1.getNext(), node2);
return node1;
} else {
node2.getNext() = mergeByRecursion(node1, node2.getNext());
return node2;
}
}
You probably don't need to use head_node var.
You can just call getNext() since the lists are already sorted.

Why can't I just do node = node.next to iterate through linked list?

I am currently doing a Cracking the Coding Interview Problem (2.4) and I am supposed to partition a linked list around a value x, such that all nodes less than x come before all nodes greater than or equal to x. However, I am really confused as to why a temporary variable "next" is needed and why is node.next nulled below it. Why can't I just do node = node.next at the end of the while loop?
I am simply creating two linked lists, before and after, and merging them together once the correct values are put into each list.
public static Node partition(Node node, int x) {
Node beforeStart = null;
Node beforeEnd = null;
Node afterStart = null;
Node afterEnd = null;
/* Partition list */
while (node != null) {
Node next = node.next;
node.next = null;
if (node.data < x) {
if (beforeStart == null) {
beforeStart = node;
beforeEnd = beforeStart;
} else {
beforeEnd.next = node;
beforeEnd = beforeEnd.next;
}
} else {
if (afterStart == null) {
afterStart = node;
afterEnd = afterStart;
} else {
afterEnd.next = node;
afterEnd = afterEnd.next;
}
}
node = next;
}
/* Merge before list and after list */
if (beforeStart == null) {
return afterStart;
}
beforeEnd.next = afterStart;
return beforeStart;
}
Why can't I just do node = node.next at the end of the while loop?
It can be done this way. After doing the partition, for each list, you need to set the last node's next pointer to NULL. This will just take two lines of code.
The example code is using next = node.next and node.next = NULL to terminate each list during the partition process, but in this case that's not needed, since the lists don't need NULL terminators until after the partition process is done.
The loop in your question removes nodes from the head of the original list, and appends them to the before list or the after list, until the original list is empty. Then it concatenates the before and after lists.
That's easy to explain and easy to understand.
It can be done without the temporary next or nulling out node.next in every iteration, but then the above description would no longer apply -- nodes would not be removed from the original list in every iteration, the before list and after list would not contain only the appropriate nodes, the operation you perform on them is not 'appending', and nodes would even appear in multiple lists for a while.
Your algorithm would suddenly be a lot more difficult to describe and understand. That is a bad thing in software development, and a bad thing in a coding interview.

Tree structure: Best way to find element and save chain of parent elements

I have a JSONObject, which could have JSONArray of same same type children. I would like to iterate over it, find the element which I need and save the chain of parent elements (e.g. found element is the child of this element, this element is the child of next element, next element is the child of root).
Currently here is my naive implementation:
private boolean found;
private void searchNode(List<JSONObject> chain,
JSONObject rootNode, JSONObject desiredFrame) {
if (found)
return;
JSONArray children = rootNode.getJSONArray("frames");
chain.add(rootNode);
for (int i = 0; i < children.length(); i++) {
JSONObject currentNode = children.getJSONObject(i);
if (currentNode.equals(desiredNode)) {
found = true;
chain.add(currentNode);
return;
}
searchNode(chain, currentNode, desiredNode);
if (!found)
chain.remove(currentNode);
}
What problems can I see:
I am not sure it will work well :)
This implementation is not obvious, It's not clean code.
I am using class field, probably I could avoid that usage
This structure could be named tree, but this one is not binary.
Some potential problems with code:
you can replace shared flag found with result of searchNode.
you are comparing a JSONObject for equals. I would recommend to use Predicate to check is it proper node or not.
rootNode.getJSONArray("frames") can returns null or empty array, but you never check it.
Also you can use Stack<> instead of List<> to track a path. It can simplify your algorithm.
Example:
private static boolean searchNode(Stack<JSONObject> chain,
JSONObject currentNode, Predicate<JSONObject> condition) throws Exception {
if (condition.test(currentNode)) {
chain.push(currentNode);
return true;
}
JSONArray children = currentNode.getJSONArray("frames");
if (children == null) {
return false;
}
for (int i = 0; i < children.length(); i++) {
if (searchNode(chain, children.getJSONObject(i), condition)) {
chain.push(currentNode);
return true;
}
}
return false;
}
Here is a better algorithm to search for your object.
You don't have to maintain a found field or pass your chain as a parameter.
Instead you use the return values of your recursive calls to build the chain once you find the object
List<JSONObject> search(JSONObject node, JSONObject searchTerm) {
if (node.equals(searchTerm)) {
List<JSONObject> chain = new List<>();
chain.add(node);
return chain;
} else {
List chain = new Collections.emptyList();
for (JSONObject child: node.getJSONArray("frames")) {
chain = search(child, searchTerm);
if (chain.length > 0) {
chain.add(0, node);
break;
}
}
return chain;
}
}

Create child nodes using recursion

I'm trying to create a hierarchy from flat data. I have the following Node definition:
public class Node {
public String name;
public List<Node> children = new ArrayList<>();
}
Given this data: [Person,Manager,Hourly,New], where the tree should be like:
Person
|--Manager
|--Hourly
|--New
I've tried the following:
public void run()
{
List<List<String>> objects = new ArrayList<>();
String[] str = {"Person","Manager","Hourly","New"};
objects.add(Arrays.asList(str)) ;
String[] str2 = {"Person","Manager","Salary"};
objects.add(Arrays.asList(str2)) ;
String[] str3 = {"Person","Manager","Salary", "New"};
objects.add(Arrays.asList(str3)) ;
// Create a Node with the sequence
myNode = new Node();
createNode(objects.get(0), 0, myNode, myNode);
LOG.debug(myNode.name);
}
And my createNode method is:
public Node createNode(List<String> seq, Integer start, Node parentNode, Node childNode)
{
// do something and return a Node?
}
But conceptually I don't understand how to maintain the structure if Java is return-by-value. What do I add to createNode so that I can add a Manager->Hourly->New hierarchy as a child to Person
You don't need both a Node return type and a Node argument to your method.
Here's one way to do it:
//in run()
myNode = new Node();
myNode.name = "Root";
createNode(objects.get(0), 0, myNode, myNode);
public void createNode(List<String> seq, Integer start, Node parentNode)
{
Node childNode = new Node();
childNode.name = seq[start];
parentNode.children.Add(childNode);
createNode(seq, start+1, childNode);
}
You don't need to return anything from createNode() -- since you have parentNode as a variable, you can add things to its children member. A call to createNode() will recursively add child nodes, following your string array to its end.
Another way to do it is like this:
public Node createNode(List<String> seq, Integer start)
{
if (start >= seq.Length) {
return null;
}
Node node = new Node();
node.name = seq[start];
node.children.Add(createNode(seq, start+1);
return node;
}
In this case, you don't need to pass in node references at all; calling createNode() will generate a new node object, fill its children tree recursively, and return the newly-generated node structure.
As I can see your defination of node is somewhat similar to adjacency list in graph.
In the Target node add the associated node in the list associated with the target node. This is true for each node belonging to all the nodes.
For each object belonging to the objects array (array parameter) in your createNode method, you need to create the Node object.
just pass an String array and the taeget node. Iterate the list and create a node. Add the node in the list.
To avoid duplicates while creating Node add them in an map. Key to the map should be String and value should be Node object. Before creating the object of node just try to get the object from the map, make the object only iff the object is not found in the map(in such a case create and add it to the map). In case object is found un the map, us the samedo not recreate it.

Traversing a deep data structure & deleting object

I have a function to traverse a complex deep HashMap structure. My problem is that when I find the desired node, and do any action on it, such as deleting it, I'm not actually doing any action on the data structure, but instead I'm operating on a copy of the data structure. I'd think a pointer such as in C++ would solve my problem, so how can I do this in Java?
The code:
private HashMap parentNode = null;
// a complex JSON string of arrays / objects, won't list for brevity
private String jsonString = ...
// parses JSON string into HashMaps for objects and Object[ ]s for arrays
private HashMap arr = (HashMap)JSON.parse(jsonString);
// find the node with an id of 27
HashMap parent = findNode(arr, "27");
// Print arr before modifying node
System.out.println(arr);
// modify parent in some way
parent = null;
// Print arr after modifying node
System.out.println(arr);
public HashMap findNode(HashMap map, String id) {
parentNode = null;
findNodeRecursive(map, id);
return parentNode;
}
public void findNodeRecursive(HashMap map, String id) {
for(Object entry : map.entrySet()){
Object value = ((Map.Entry)entry).getValue();
if((value instanceof String) && ((String)value).equals(id))
parentNode = map;
else if(value instanceof HashMap)
findNodeRecursive((HashMap)value,id);
else if(value instanceof Object[])
for(int i=0; i<((Object[])value).length; i++)
findNodeRecursive( (HashMap)(((Object[])value)[i]) ,id);
}
}
To delete the node you want (parent), change your
parent = null;
to
arr.remove(parent);
Setting it to null does not delete anything, simply changes the reference that once was pointing to the node, back to null. To delete, you need to do it explicitly by using the HashMap.remove() method

Categories