One-way sync of two hierarchies - data-structures

I'm hoping to write an algorithm to synchronize two hierarchical structures. These structures could be object graphs, data stored in relational database tables, etc (even two different structures, so long as they have comparable keys). The synchronization will be one-way, i.e., one structure will be the prototype, and the other will be modified to match.
Let's say we have a sync function. It would need to accept the following:
objA -- the prototype
objB -- the object to be modified
keyA -- key generating function for objA
keyB -- key generating function for objB
addB -- function to create an objB (returns id of new objB)
setB -- function to update objB
remB -- function to delete an objB
parB -- id of objB's parent -- this is passed to addB for context
So we have this:
let sync (objA:'a) (objB:'b) (keyA:'a -> 'k) (keyB:'b -> 'k)
(addB:'p * 'a -> 'p) (setB:'a * 'b -> unit) (remB:'b -> unit)
(parB:'p) = ...
Now here's where I'm having trouble. 'a and 'b are hierarchical, so the function needs to know which properties of 'a and 'b it should traverse (once it compares their keys and decides they match thus far and should be further traversed). For these "child" properties, it needs all the same arguments passed to sync, but for their respective types.
This is when it became apparent this is a data structure problem. How can I chain together this information such that the root object can be passed to sync and it can traverse the graphs downward? My initial thought was to incorporate all of the arguments into a class, which would have a children property (a ResizeArray of the same type). But with various properties having different types, I couldn't figure out a way to make it work, short of throwing types out the window and making most or all of the type arguments obj.
So here are my questions:
Is there a well-established method for doing this already (I haven't been able to find anything)
What data structure might I use to encapsulate the data necessary to make this work?
I've tried my best to explain this thoroughly, but if anything remains unclear, please ask, and I'll try to provide better information.

I'm sure this is oversimplifying it but here's my idea.
If this is a DAG you could do a breadth-first traversal of objA. When you enqueue a node from objA include objB and any other information you need (tuple). Then when you dequeue you fix up objB.
You could use a discriminated union to handle different child types in your enqueueing.

Generate diffgrams from the two data structures and map the transforms to the transformed problem.

Related

Data Structure - Abstract data type VS Concrete data type

Abstract data type (ADT) : Organized data and operations on this data
Examples : Stack, Queue
what's meaning of Concrete data type (CDT)?
please explain by Examples.
One way to understand it is that an ADT is a specification of an object with certain methods.
For example if we talk about a List we are referring to an object that performs list operations such as:
add to the beginning
add to the end
insert at position
size
etc..
A "concrete data type" in this context would refer to the actual Data Structure you use to implement the list.
For example, one implementation of a List is to create nodes with a value and next pointer to point to the next node in the list.
Another is to have a value array, and a next array to tell you where the next node is (this is a more popular implementation for parallelism).
And yet another is to have a dynamic array (known as an ArrayList in Java) where you use an array till it fills up and then you duplicate it's size and copy the values to the new array.
So the concrete data type refers to the data structure actually being used, whereas the ADT is the abstract concept like List, Dictionary, Stack, Queue, Graph, etc..
There are many ways to implement an ADT.

How to join two publishers based on a common attribute and construct a single publisher out of it, in Spring reactor/ web flux?

Suppose I have two fluxes Flux<Class1> and Flux<Class2> and both Class1 and Class2 have a common attribute, say "id".
The use case is to join the two fluxes based on the common attribute "id" and construct a single Flux<Tuple<Class1, Class2>>, similar to joining two sql tables.
-There will always be a 1 to 1 match, for the attribute id, between the two fluxes.
-The fluxes won't contain more than 100 objects.
-The fluxes are not ordered by id.
How do I achieve this in Project Reactor/Spring web flux?
Assuming that:
both collections aren't very big (you can hold them in memory without risking OOM issues)
they're not sorted by id
each element in a collection has its counterpart in the other
First, you should make those Class1, Class2 implement Comparable or at least prepare a comparator implementation that you can use to sort them by their id.
Then you can use the zip operator for that:
Flux<Class1> flux1 = ...
Flux<Class2> flux2 = ...
Flux<Tuple2<Class1,Class2>> zipped = Flux.zip(flux1.sort(comparator1), flux2.sort(comparator2));
Tuple2 is a Reactor core class that lets you access each element of the Tuple like this
Tuple2<Class1,Class2> tuple = ...
Class1 klass1 = tuple.getT1();
Class2 klass2 = tuple.getT2();
In this case, sort will buffer all elements and this might cause memory/latency issues if the collections are large. Depending on how the ordering is done in those collections (let's say the ordering is not guaranteed, but those were batch inserted), you could also buffer some of them (using window) and do the sorting on each window (with sort).
Of course, ideally, being able to fetch both already sorted would avoid buffering data and would improve backpressure support in your application.
I think this should work with the following constraints:
the 2nd Flux needs to emit the same elements to all subscribers since it gets subscribed to over and over again.
this is basically the equivalent of a nested loop join so highly inefficient for large fluxes.
every element of the first Flux has a matching element in the second one.
flux1.flatMap(
f1 -> flux2.filter(f2 -> f2.id.equals(f1.id)).take(1)) // take the first with matching id
.map(f2 -> Tuple.of(f1,f2))) // convert to tuple.
writen without IDE. Consider pseudo code.

Why does Map<K,V> not extends Function<K,V>?

While playing around with the new Java 8 Stream API I got to wondering, why not:
public interface Map<K,V> extends Function<K, V>
Or even:
public interface Map<K,V> extends Function<K, V>, Predicate<K>
It would be fairly easy to implement with default methods on the Map interface:
#Override default boolean test(K k) {
return containsKey(k);
}
#Override default V apply(K k) {
return get(k);
}
And it would allow for the use of a Map in a map method:
final MyMagicMap<String, Integer> map = new MyMagicHashMap<>();
map.put("A", 1);
map.put("B", 2);
map.put("C", 3);
map.put("D", 4);
final Stream<String> strings = Arrays.stream(new String[]{"A", "B", "C", "D"});
final Stream<Integer> remapped = strings.map(map);
Or as a Predicate in a filter method.
I find that a significant proportion of my use cases for a Map are exactly that construct or a similar one - as a remapping/lookup Function.
So, why did the JDK designers not decide to add this functionality to the Map during the redesign for Java 8?
The JDK team was certainly aware of the mathematical relationship between java.util.Map as a data structure and java.util.function.Function as a mapping function. After all, Function was named Mapper in early JDK 8 prototype builds. And the stream operation that calls a function on each stream element is called Stream.map.
There was even a discussion about possibly renaming Stream.map to something else like transform because of possible confusion between a transforming function and a Map data structure. (Sorry, can't find a link.) This proposal was rejected, with the rationale being the conceptual similarity (and that map for this purpose is in common usage).
The main question is, what would be gained if java.util.Map were a subtype of java.util.function.Function? There was some discussion in comments about whether subtyping implies an "is-a" relationship. Subtyping is less about "is-a" relationships of objects -- since we're talking about interfaces, not classes -- but it does imply substitutability. So if Map were a subtype of Function, one would be able to do this:
Map<K,V> m = ... ;
source.stream().map(m).collect(...);
Right away we're confronted with baking in the behavior of what is now Function.apply to one of the existing Map methods. Probably the only sensible one is Map.get, which returns null if the key isn't present. These semantics are, frankly, kind of lousy. Real applications are probably going to have to write their own methods that supply key-missing policy anyway, so there seems to be very little advantage of being able to write
map(m)
instead of
map(m::get)
or
map(x -> m.getOrDefault(x, def))
The question is “why should it extend Function?”
Your example of using strings.map(map) doesn’t really justify the idea of changing the type inheritance (implying adding methods to the Map interface), given the little difference to strings.map(map::get). And it’s not clear whether using a Map as a Function is really that common that it should get that special treatment compared to, e.g. using map::remove as a Function or using map::get of a Map<…,Integer> as ToIntFunction or map::get of a Map<T,T> as BinaryOperator.
That’s even more questionable in the case of a Predicate; should map::containsKey really get a special treatment compared to map::containsValue?
It’s also worth noting the type signature of the methods. Map.get has a functional signature of Object → V while you suggests that Map<K,V> should extend Function<K,V> which is understandable from a conceptional view of maps (or just by looking at the type), but it shows that there are two conflicting expectations, depending on whether you look at the method or at the type. The best solution is not to fix the functional type. Then you can assign map::get to either Function<Object,V> or Function<K,V> and everyone is happy…
Because a Map is not a Function. Inheritance is for A is a B relationships. Not for A can be the subject of various kinds of B relationships.
To have a function transforming a key to its value, you just need
Function<K, V> f = map::get;
To have a predicate testing if an object is contained in a map, you just need
Predicate<Object> p = map::contains;
That is both clearer and more readable than your proposal.

how to record reflexive entity in DB?

I have a reflexive entity, a classic parent - children.
This hierarchy is edited by the user in the front-end and then passed back to the backend.
The only way I've found to record that kind of array with doctrine/symfony2 is this way (ps no code, logic here):
getting the modified array array_result
getting all the objects from the bdd (via the repository, I get an array of all the objects) array_bdd
loop over array_result, each element of the modified array
if element.id can be found in array_bdd then
comparing all the properties
if there is a difference in the properties, I modify the object in array_bdd and persist it
end of loop
flush
It's seems a bit heavy to me but from what I've read I couldn't find another way.
Is it correct to perform like this with doctrine ?

Reordering validation in icefaces ace:tree

I'm trying to use reordering feature of ace:tree component in icefaces. I have 3 types of nodes in my tree. My goal is to put some constraints on the tree.
Let's say i have node types A, B and C.
A is the root node
A can have only B type children
B can have children of type B or C
I want to block reordering when these constraints are not met. How one would apply such validation in ace:tree?
EDIT1
I forgot to mention that i have my validation implemented but what's not working is validation when using drag and drop feature (view updates to invalid state, model stays as it was when doing invalid operation) I need a clever way to refresh my view.
This can be done, without knowing how your code looks like, you have probably built your tree structure using nodes like
this one.
Therefore, you can constrain the data model (the parent nodes from the list) to accept only the values that you want.
You can signal to the user that an operation is not permitted using FacesMessage.

Resources