I have multiple dynamic objects that (most of the time) differ in only a few values. I want to be able to merge these objects into one single object and in case of a conflict (two values aren’t the same) then I want these to be stored in a collection or another dynamic object (if possible).
I’m usisng the expandoObject class so I can cast my objects into a dictionairy and try to merge that but I haven’t found any articles or sources on merging dictionairies that create collections with conflicts.
Is there a way to do this in an easy to implement and efficient fashion?
I’ll post some code samples to give you a small idea of what I’m trying to accomplish
//returns a dynamic object from JSON (output from DataBase)
JsonReader reader = new JsonReader();
dynamic object = reader.Read(input);
//Creates a dictionairy with all the fieldnames and values.
IDictionary<string, dynamic> properties = (IDictionary<string, dynamic>)object;
//My goal is to merge multiple of these objects into one single object and
//creating collections when values are different from each other.
Your problem seems to be based on the IDictionary<> interface. It assumes there is only one value for each key. I believe that you want rather to move to a LINQ-ish
IEnumerable<IGrouping<TKey,TValue>>that represents a list of keyed value collections.LINQ emits such objects when you do a .GroupBy or .ToLookup calls.
Let’s play then:
Of course it will not work, but I’ve written it to see what problems would it expose. First – you will probably get duplicate keys when Concat’ing. Then not all keys are in A and B, so the indexers woudl throw. Next, I happened to assume that the original objects were string-to-one-value, and you are likely to work on already-collided objectts. Then, this uses only 2 A/B objects, while you may want to work on multiple..
Look there. I’ve taken all dictionaries and “just paired them up” according to their Keys. As a result, I’ve got a lookup that binds each existing Key to a series of Values that were earlier assigned to that key. The resulting
matched_by_keysis an Enumerable, not a dictionary, so it was later translated to it. Look at the parameters to ToDictionary: the Group is itself a IEnumerable just a key had to be pointed out and the group is unchanged.Still, the input works only on IDictionary that is single-valued. If you need to do such things with multi-valued inputs too, you can easily transalte IDictionaries to lookups and perform the operations on them:
Note how the final groups had to be now translated. In this example, groupsis not
IEnumerable<Value>, butIEnumerable<IEnumerable<Value>>becuase the inputs were allowed to be multi-valued, even if they had only 1 value. So, thit had to be flattened, and this is done by SelectMany. That in turn didnt need to project anything, as the item was already IEnumerable, so a s=>s was enough.Using different overloads of GroupBy, ToLookup, and ToDictionary you may achieve many useful effects. Play with the overloads!