Find nested hierarchies using boolean matrix - c#

I have a created a Node Builder to fetch how n elements are connected to one another. It is a parent child hierarchy represented in Node Tree.
I am using tree builder like below code to find best two chains.
Below is the code:
public class NodeBuilder
{
private readonly List<IItem> _nestedItems;
private readonly IFactory<IItem> _factory;
private readonly NodeEqualityComparer _comparer;
private readonly List<Node> _nodes;
private WeightedComparer _weightedComparer;
private NodeComparer _nodeComparer;
private readonly NodeItemComparer _nodeItemComparer;
public NodeBuilder(List<IItem> nestedItems, IFactory<IItem> factory)
{
_nestedItems = nestedItems;
_factory = factory;
_comparer = new NodeEqualityComparer();
_nodeComparer = new NodeComparer();
_nodes = new List<Node>();
_weightedComparer=new WeightedComparer();
_nodeItemComparer = new NodeItemComparer(_factory.Comparer);
}
public IEnumerable<List<int>> GetTopChains(int collections)
{
if (_nodes.Count == 0) BuildNodes(collections);
var collection= GetIndexes().ToList();
collection.Sort(_weightedComparer);
return collection.Take(collections);
}
public class WeightedComparer : IComparer<List<int>>
{
public int Compare(List<int> x, List<int> y)
{
if (x == y) return 0;
if (x == null) return 1;
if (y == null) return -1;
return y.Count - x.Count;
}
}
private IEnumerable<List<int>> GetIndexes()
{
Dictionary<IItem,List<int>> indexers = new Dictionary<IItem, List<int>>();
_nodes.Sort(_nodeItemComparer);
foreach (var node in _nodes)
{
List< int> indexs=new List<int>();
int currSize = node.ChainSize;
var temp = node;
while (temp != null)
{
int index = _nestedItems.IndexOf(temp.Item);
if (index != -1) indexs.Add(index);
currSize--;
var temps = new List<Node>(temp.Childs.Where(x => x.ChainSize == currSize));
temps.Sort(_nodeComparer);
Dictionary<Node,List<int>> subIndexes = new Dictionary<Node, List<int>>();
if (!temps.Any()) temp = null;
foreach (var subTemp in temps)
{
var key = subTemp.Item;
if (indexers.ContainsKey(key))
{
var newList = new List<int>();
newList.AddRange(indexs);
newList.AddRange(indexers[key]);
subIndexes.Add(subTemp, newList);
}
if (subIndexes[subTemp].Count == node.ChainSize)
{
temp = subTemp;
indexers.Remove(subTemp.Item);
}
else
{
temp = null;
}
}
}
indexs = indexs.Distinct().ToList();
indexers.Add(node.Item,indexs);
}
return indexers.Values;
}
private void BuildNodes(int collections)
{
int total = _factory.TotalItems;
for (int i = collections * _factory.TotalItems - 1; i >= 0; i--)
{
var searchNode = new Node(_nestedItems[i], _factory.EqualityComparer);
Node node1 = _nodes.SingleOrDefault(x => _comparer.Equals(x, searchNode));
if (node1 == null)
{
node1 = searchNode;
node1.ChainSize = total;
_nodes.Add(node1);
}
}
for (int i = 0; i < collections * _factory.TotalItems; i++)
{
var searchNode = new Node(_nestedItems[i], _factory.EqualityComparer);
Node node1 = _nodes.SingleOrDefault(x => _comparer.Equals(x, searchNode));
for (int j = 0; j < collections * _factory.TotalItems; j++)
{
searchNode = new Node(_nestedItems[j], _factory.EqualityComparer);
Node node2 = _nodes.SingleOrDefault(x => _comparer.Equals(x, searchNode));
if (node2 == null)
{
node2 = searchNode;
_nodes.Add(node2);
}
if (_nestedItems[i].Constraint(_nestedItems[j]))
{
if (node1 != null)
{
int temp = node1.ChainSize - 1;
node2.ChainSize = temp;`enter code here`
if (!node1.Childs.Contains(node2, new NodeEqualityComparer()))
node1.Childs.Add(node2);
}
}
}
}
}
}
public class NodeItemComparer:IComparer<Node>
{
private readonly IComparer<IItem> _factoryComparer;
public NodeItemComparer(IComparer<IItem> factoryComparer)
{
_factoryComparer = factoryComparer;
}
public int Compare(Node x, Node y)
{
if (x == null & y == null) return 0;
if (x == y) return 0;
if (x == null) return 1;
if (y == null) return -1;
return _factoryComparer.Compare(y.Item, x.Item);
}
}
public class NodeComparer:IComparer<Node>
{
public int Compare(Node x, Node y)
{
if (x == null & y == null) return 0;
if (x == y) return 0;
if (x == null) return 1;
if (y == null) return -1;
return y.ChainSize - x.ChainSize;
}
}
public class NodeEqualityComparer : IEqualityComparer<Node>
{
public bool Equals(Node x, Node y)
{
if (x == null & y == null) return true;
if (x == y) return true;
if (x != y) return false;
return x.Equals(y);
}
public int GetHashCode(Node obj)
{
return obj.GetHashCode();
}
}
public class Node : IEquatable<Node>
{
public IItem Item { get; }
private readonly IEqualityComparer<IItem> _comparer;
public int ChainSize { get; set; }
public IList<Node> Childs { get; private set; }
public Node(IItem item, IEqualityComparer<IItem> comparer)
{
Item = item;
_comparer = comparer;
Childs = new List<Node>();
}
public override string ToString()
{
return Item.ItemName;
}
public bool Equals(Node other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return _comparer.Equals(Item, other.Item);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Node)obj);
}
public override int GetHashCode()
{
return (Item != null ? Item.GetHashCode() : 0);
}
public static bool operator ==(Node left, Node right)
{
return Equals(left, right);
}
public static bool operator !=(Node left, Node right)
{
return !Equals(left, right);
}
}
I am looking for a ways to traverse the tree and find two hierarchical connected items.

Related

How to modify my CustLinkedList to implement insert more efficiently

I created a custom linked list on a whiteboard, for learning purposes.
CustDoublyLinkedList class with the nested Node class, but when it is time to insert, at the specified index method must loop through until it get to an index to insert. I want to insert directly without using loop as my Add or PushFront methods work.
I also added some more method like IndexOf and Contain methods for the list
CustDoublyLinkedList<int> myList = new();
myList.Add(12);
myList.Add(13);
myList.Add(14);
myList.Add(45);
myList.Add(28);
myList.Add(120);
myList.PushFront(32);
myList.Insert(3,1500);
for (int i = 0; i < myList.Count; i++)
{
Console.WriteLine(myList[i]);
}
class CustDoublyLinkedList<T>
{
private class Node
{
public T Element { get; set; }
public Node NextNode { get; set; }
public Node PrevNode { get; set; }
public Node(T data)
{
this.Element = data;
this.PrevNode = null;
this.NextNode = null;
}
public Node(T data, Node prevNode): this(data)
{
prevNode.NextNode = this;
}
public Node(T data, Node prevNode, Node nextNode) : this(data, prevNode)
{
nextNode.PrevNode = this;
}
}
private Node head;
private Node tail;
private int counter;
public CustDoublyLinkedList()
{
this.head = null;
this.tail = null;
this.counter = 0;
}
public void Insert(int index, T item)
{
if (index == 0)
{
throw new ArgumentOutOfRangeException("You Can Push with PushFront Method at Index: " + index);
}
if (index < 0 || index >= this.counter)
{
throw new ArgumentOutOfRangeException("invalid Index: " + index);
}
Node newNode = new(item);
Node currentNode = this.head;
for (int i = 0; i < index - 1; i++)
{
currentNode = currentNode.NextNode;
}
newNode.NextNode = currentNode.NextNode;
newNode.PrevNode = currentNode.PrevNode;
currentNode.NextNode = newNode;
this.counter++;
}
public void Add(T item)
{
if (this.head == null)
{
this.head = new(item);
this.tail = this.head;
}
else
{
Node newNode = new(item, this.tail);
this.tail = newNode;
}
this.counter++;
}
public void PushFront(T item)
{
Node newNode = new(item);
newNode.NextNode = this.head;
newNode.PrevNode = null;
if(this.head != null)
{
this.head.PrevNode = newNode;
}
this.head = newNode;
this.counter++;
}
public bool Contain(T item)
{
int index = IndexOf(item);
if (index != -1)
{
return true;
}
return false;
}
public int IndexOf(T item)
{
Node currentNode = this.head;
int index = 0;
while(currentNode != null)
{
if (object.Equals(currentNode.Element, item))
{
return index;
}
currentNode = currentNode.NextNode;
index++;
}
return -1;
}
public int Count
{
get { return this.counter; }
}
public T this[int index]
{
get
{
if (index < 0 || index >= this.counter)
{
throw new IndexOutOfRangeException("Invalid Index: " + index);
}
Node currentNode = this.head;
for (int i = 0; i < index; i++)
{
currentNode = currentNode.NextNode;
}
return currentNode.Element;
}
set
{
if (index < 0 || index >= this.counter)
{
throw new IndexOutOfRangeException("Invalid Index: " + index);
}
Node currentNode = this.head;
for (int i = 0; i < index; i++)
{
currentNode = currentNode.NextNode;
}
currentNode.Element = value;
}
}
}
You are looking for a Skip List
With this you can drive your insert requirement to O(log N) on average while still maintaining a linked list structure

Exchange of two elements of a doubly linked list C#

How can I swap two elements of a two-linked list(by switching links)? I realized that I need to consider four cases: change with the first / last elements, change neighboring elements, and all other cases.
The cell structure is as follows:
public class Item<T>
{
private T _Data;
private Item<T> _Next;
private Item<T> _Prev;
public T Value
{
get { return _Data; }
set { this._Data = value; }
}
public Item(T Data)
{
this._Data = Data;
}
public Item()
{
this._Data = default;
}
public Item<T> Next
{
get { return this._Next; }
set { this._Next = value; }
}
public Item<T> Prev
{
get { return this._Prev; }
set { this._Prev = value; }
}
}
This is an implementation attempt. What's wrong?(Here I also do insert sort, but it all depends on the exchange of two elements)
public override D_List<T> Sorting(D_List<T> a)
{
for (int top = 1; top < a.Count; top++)
{
int k = top;
while (k > 0 && a[k-1] > a[k])
{
k--;
}
if (k == 0)
{
a[top].Prev.Next = a[top].Next;
a[top].Next.Prev = a[top].Prev;
a[top].Next = a[k];
a[top].Prev = null;
a[k].Prev = a[top];
}
else if(k == a.Count - 2)
{
a[k].Prev.Next = a[top];
a[top].Prev = a[k].Prev;
a[k].Next = null;
a[k].Prev = a[top];
}
else if(k+1 == top)//стоят подряд
{
a[k].Prev.Next = a[top];
a[top].Prev = a[k].Prev;
a[k].Next = a[top].Next;
a[top].Next = a[k];
a[k].Next.Prev = a[k];
}
else
{
a[k].Prev = a[top];
a[top].Prev.Next = a[top].Next;
a[top].Next.Prev = a[top].Prev;
a[top].Prev = a[k].Prev;
a[top].Next = a[k];
a[top].Next.Prev = a[top];
}
}
return a;
}

C# how to modify the linkedlist node property?

I have a linkedlist class like follows:
public class DbNode<T>
{
private T _data;
private DbNode<T> _prev;
private DbNode<T> _next;
public T Data
{
get { return this._data; }
set { this._data = value; }
}
public DbNode<T> Prev
{
get { return this._prev; }
set { this._prev = value; }
}
public DbNode<T> Next
{
get { return this._next; }
set { this._next = value; }
}
public DbNode(T data, DbNode<T> prev, DbNode<T> next)
{
this._data = data;
this._prev = prev;
this._next = next;
}
public DbNode(T data, DbNode<T> prev)
{
this._data = data;
this._prev = prev;
this._next = null;
}
public DbNode(DbNode<T> next)
{
this._data = default(T);
this._next = next;
this._prev = null;
}
public DbNode(T data)
{
this._data = data;
this._prev = null;
this._next = null;
}
public DbNode()
{
this._data = default(T);
this._prev = null;
this._next = null;
}
}
public class DbLinkedList<T>
{
private DbNode<T> _head;
public DbNode<T> Head
{
get { return this._head; }
set { this._head = value; }
}
public DbLinkedList()
{
Head = null;
}
public T this[int index]
{
get
{
return this.GetItemAt(index);
}
}
public bool IsEmpty()
{
return Head == null;
}
public T GetItemAt(int i)
{
if (IsEmpty())
{
Console.WriteLine("The double linked list is empty.");
return default(T);
}
DbNode<T> p = new DbNode<T>();
p = Head;
if (0 == i)
{
return p.Data;
}
int j = 0;
while (p.Next != null && j < i)
{
j++;
p = p.Next;
}
if (j == i)
{
return p.Data;
}
else
{
Console.WriteLine("The node dose not exist.");
return default(T);
}
}
public int Count()
{
DbNode<T> p = Head;
int length = 0;
while (p != null)
{
length++;
p = p.Next;
}
return length;
}
public void Clear()
{
this.Head = null;
}
public void AddAfter(T item, int i)
{
if (IsEmpty() || i < 0)
{
Console.WriteLine("The double linked list is empty or the position is uncorrect.");
return;
}
if (0 == i)
{
DbNode<T> newNode = new DbNode<T>(item);
newNode.Next = Head.Next;
Head.Next.Prev = newNode;
Head.Next = newNode;
newNode.Prev = Head;
return;
}
DbNode<T> p = Head;
int j = 0;
while (p != null && j < i)
{
p = p.Next;
j++;
}
if (j == i)
{
DbNode<T> newNode = new DbNode<T>(item);
newNode.Next = p.Next;
if (p.Next != null)
{
p.Next.Prev = newNode;
}
newNode.Prev = p;
p.Next = newNode;
}
else
{
Console.WriteLine("The position is uncorrect.");
}
}
public void AddBefore(T item, int i)
{
if (IsEmpty() || i < 0)
{
Console.WriteLine("The double linked list is empty or the position is uncorrect.");
return;
}
if (0 == i)
{
DbNode<T> newNode = new DbNode<T>(item);
newNode.Next = Head;
Head.Prev = newNode;
Head = newNode;
return;
}
DbNode<T> n = Head;
DbNode<T> d = new DbNode<T>();
int j = 0;
while (n.Next != null && j < i)
{
d = n;
n = n.Next;
j++;
}
if (n.Next == null)
{
DbNode<T> newNode = new DbNode<T>(item);
n.Next = newNode;
newNode.Prev = n;
newNode.Next = null;
}
else
{
if (j == i)
{
DbNode<T> newNode = new DbNode<T>(item);
d.Next = newNode;
newNode.Prev = d;
newNode.Next = n;
n.Prev = newNode;
}
}
}
public void AddLast(T item)
{
DbNode<T> newNode = new DbNode<T>(item);
DbNode<T> p = new DbNode<T>();
if (Head == null)
{
Head = newNode;
return;
}
p = Head;
while (p.Next != null)
{
p = p.Next;
}
p.Next = newNode;
newNode.Prev = p;
}
public T RemoveAt(int i)
{
if (IsEmpty() || i < 0)
{
Console.WriteLine("The double linked list is empty or the position is uncorrect.");
return default(T);
}
DbNode<T> q = new DbNode<T>();
if (0 == i)
{
q = Head;
Head = Head.Next;
Head.Prev = null;
return q.Data;
}
DbNode<T> p = Head;
int j = 0;
while (p.Next != null && j < i)
{
j++;
q = p;
p = p.Next;
}
if (i == j)
{
p.Next.Prev = q;
q.Next = p.Next;
return p.Data;
}
else
{
Console.WriteLine("The position is uncorrect.");
return default(T);
}
}
public int IndexOf(T value)
{
if (IsEmpty())
{
Console.WriteLine("The list is empty.");
return -1;
}
DbNode<T> p = new DbNode<T>();
p = Head;
int i = 0;
while (p.Next != null && !p.Data.Equals(value))
{
p = p.Next;
i++;
}
return i;
}
public void Reverse()
{
DbLinkedList<T> tmpList = new DbLinkedList<T>();
DbNode<T> p = this.Head;
tmpList.Head = new DbNode<T>(p.Data);
p = p.Next;
while (p != null)
{
tmpList.AddBefore(p.Data, 0);
p = p.Next;
}
this.Head = tmpList.Head;
tmpList = null;
}
public string ReverseByPrev()
{
DbNode<T> tail = GetNodeAt(Count() - 1);
StringBuilder sb = new StringBuilder();
sb.Append(tail.Data.ToString() + ",");
while (tail.Prev != null)
{
sb.Append(tail.Prev.Data + ",");
tail = tail.Prev;
}
return sb.ToString().TrimEnd(',');
}
private DbNode<T> GetNodeAt(int i)
{
if (IsEmpty())
{
Console.WriteLine("The list is empty.");
return null;
}
DbNode<T> p = new DbNode<T>();
p = this.Head;
if (0 == i)
{
return p;
}
int j = 0;
while (p.Next != null && j < i)
{
j++;
p = p.Next;
}
if (j == i)
{
return p;
}
else
{
Console.WriteLine("The node does not exist.");
return null;
}
}
public T Fisrt()
{
return this.GetItemAt(0);
}
public T Last()
{
return this.GetItemAt(this.Count() - 1);
}
}
And I alse have a class as Product which contains properties:ProductID and ProductValue:
public class Product
{
private byte _productID;
public byte ProductID
{
get { return _productID; }
set
{
_productID = value;
NotifyPropertyChanged("ProductID");
}
}
private UInt16 _productValue;
public UInt16 ProductValue
{
get { return _productValue; }
set
{
_productValue = value;
NotifyPropertyChanged("ProductValue");
}
}
}
I have another listbox to which I want to add the Product when I click the TreeView:
MyLinkList<Product> myLinkList = new MyLinkList<Product>();
private void MenuItem_OnClick(object sender, RoutedEventArgs e)
{
var item = this.TreeView.SelectedItem as Product;
listbox.Items.Add(item);
myLinkList.Append(item);
}
Now the problem is I want to modify the item's property selected to add based on the former one. For example: if the former one's ProductID is 1, then this SelectedItem.ProductValue = FormerItem.ProductValue + 1, how I suppose to do this? Thanks!

Randomly generate trees for unit testing

I want to randomly generate trees (not BST) for unit testing of my code. I have tried it in a number of ways but somehow after generation of 3 -4 trees there is an exception or code goes into infinite loop. I am using random numbers for edges and node values.
I have also tried queue approach where I fill up the queue with random numbers and then dequeue nodes and randomly select the old node from the existing items in the queue and then connect this new node.
Does anybody know how to do this in C# in more better and succinct way?
EDIT
public class Tree
{
public Node Root { get; private set; }
public readonly Dictionary<long, Node> Nodes = new Dictionary<long, Node>();
public readonly Dictionary<string, long> SumDictionary = new Dictionary<string, long>();
public readonly Dictionary<long, long> FDictionary = new Dictionary<long, long>
{
{0, 1},
{1, 1}
};
public long Query(long n)
{
long s = 0;
Dfs();
for (int i = 1; i <= n; i++)
{
for (int j = i; j <= n; j++)
{
var lvalue = GetLValue(i, j);
if (i != j)
{
lvalue *= 2;
}
s += lvalue;
if (s >= Mod)
{
s %= Mod;
}
}
}
return s;
}
private long GetLValue(int a, int b)
{
var key = string.Format("{0}-{1}", a, b);
if (SumDictionary.ContainsKey(key))
{
return Fvalue(SumDictionary[key]);
}
var aKey = string.Format("{0}-{1}", 1, a);
var bKey = string.Format("{0}-{1}", 1, b);
var sumA = SumDictionary[aKey];
var sumB = SumDictionary[bKey];
var lca = Lca(a, b);
if (lca != a && lca != b)
{
return Fvalue(sumA + sumB - SumDictionary[string.Format("{0}-{1}", lca, lca)]);
}
long bigSum, smallSum;
if (sumA > sumB)
{
bigSum = sumA;
smallSum = sumB;
}
else
{
bigSum = sumB;
smallSum = sumA;
}
var sumAtoB = bigSum - (smallSum - Nodes[smallSum].Value);
return Fvalue(sumAtoB);
}
public void AddNode(long a, long b)
{
Node nodea, nodeb;
if (Nodes.ContainsKey(a))
{
nodea = Nodes[a];
}
else
{
nodea = new Node { Value = a };
Nodes.Add(a, nodea);
}
if (Nodes.ContainsKey(b))
{
nodeb = Nodes[b];
}
else
{
nodeb = new Node { Value = b };
Nodes.Add(b, nodeb);
}
nodea.ReachableNodes.Add(b, nodeb);
nodeb.ReachableNodes.Add(a, nodea);
if (Root == null)
{
Root = nodea;
}
}
public long? Lca(int a, int b)
{
bool found = false;
return TraverseForLca(Root, null, a, b, ref found);
}
private long? TraverseForLca(Node node, Node prev, long a, long b, ref bool found)
{
if (node == null)
{
return null;
}
if (node.Value == a)
{
return a;
}
if (node.Value == b)
{
return b;
}
long? f = null;
foreach (KeyValuePair<long, Node> reachableNode in node.ReachableNodes)
{
var n = reachableNode.Value;
if (prev != null && n.Value == prev.Value)
{
continue;
}
long? lca = TraverseForLca(n, node, a, b, ref found);
if (found)
{
return lca;
}
if (lca != null && f == null)
{
f = lca;
}
else if (lca != null)
{
found = true;
return node.Value;
}
}
return f;
}
public void Dfs()
{
TravelForDfs(Root, null, 0);
}
private void TravelForDfs(Node node, Node prev, long recSum)
{
if (node == null)
{
return;
}
var key = string.Format("{0}-{1}", prev != null ? prev.Value : node.Value, node.Value);
var iKey = string.Format("{0}-{1}", node.Value, node.Value);
var weight = node.Weight;
if (weight >= Mod)
{
weight %= Mod;
}
if (!SumDictionary.ContainsKey(iKey))
{
SumDictionary.Add(iKey, weight);
}
weight = recSum + node.Weight;
if (weight >= Mod)
{
weight %= Mod;
}
foreach (KeyValuePair<long, Node> reachableNode in node.ReachableNodes)
{
var n = reachableNode.Value;
if (prev != null && n.Value == prev.Value)
{
if (!SumDictionary.ContainsKey(key))
{
SumDictionary.Add(key, weight);
}
continue;
}
if (!SumDictionary.ContainsKey(key))
{
SumDictionary.Add(key, weight);
}
TravelForDfs(n, node, weight);
}
}
public long Fvalue(long n)
{
if (n == 1 || n == 0)
{
return 1;
}
long a, b;
if (FDictionary.ContainsKey(n - 1))
{
a = FDictionary[n - 1];
}
else
{
a = Fvalue(n - 1);
if (!FDictionary.ContainsKey(n - 1))
{
FDictionary.Add(n - 1, a);
}
}
if (FDictionary.ContainsKey(n - 2))
{
b = FDictionary[n - 2];
}
else
{
b = Fvalue(n - 2);
if (!FDictionary.ContainsKey(n - 2))
{
FDictionary.Add(n - 2, b);
}
}
if (!FDictionary.ContainsKey(n))
{
FDictionary.Add(n, a + b);
}
var s = a + b;
if (s >= Mod)
{
s %= Mod;
}
return s;
}
}
It should just generate a tree
Does this tree meet your requirements?
public class TreeNode<T>
{
public T Value { get; set; }
public List<TreeNode<T>> Childs { get; }
public TreeNode()
{
Childs = new List<TreeNode<T>>();
}
}
public class TreeGenerator
{
private readonly int maxChilds;
private readonly Random rnd = new Random();
public TreeGenerator(int maxChilds)
{
this.maxChilds = maxChilds;
}
public TreeNode<T> CreateTree<T>(int maxDepth, Func<T> valueGenerator)
{
var node = new TreeNode<T>();
node.Value = valueGenerator();
if (maxDepth > 0)
{
var childsCount = rnd.Next(maxChilds);
for (var i = 0; i < childsCount; ++i)
node.Childs.Add(CreateTree(maxDepth - 1, valueGenerator));
}
return node;
}
public static void Demo()
{
var rnd = new Random();
var generator = new TreeGenerator(3 /* max childs count*/);
var tree = generator.CreateTree(4 /*max depth*/, () => rnd.Next() /*node value*/);
}
}

Merge Xml files

I need to merge a xml of unknown strucutre. The request is that the hierarchy won't change:
XDocument xDoc1 = XDocument.Parse(#"<Root>
<LeafA>
<a>item1</a>
</LeafA>
<LeafA>
<b>item3</b>
</LeafA>
</Root>");
XDocument xDoc2 = XDocument.Parse(#"<Root>
<LeafA>
<a>item2</a>
</LeafA>
<LeafA>
<b>item4</b>
</LeafA>
</Root>");
Merge(xDoc1.Root, xDoc2.Root);
so far i have
void Merge(XElement left, XElement right)
{
foreach (var node in right.Elements())
{
if (left.Element(node.Name.LocalName) == null)
{
left.Add(node);
}
}
foreach (var x in right.Elements().Where(r => left.Element(r.Name.LocalName) != null))
{
Merge(left.Element(x.Name.LocalName),x);
}
}
This gives me the output of
<Root>
<LeafA>
<a>item1</a>
<b>item4</b>
</LeafA>
<LeafA>
<b>item3</b>
</LeafA>
</Root>
but it has to be
<Root>
<LeafA>
<a>item1</a>
<a>item2</a>
</LeafA>
<LeafA>
<b>item3</b>
<b>item4</b>
</LeafA>
</Root>
This solved my problem:
public static void Merge(XElement left, XElement right)
{
foreach (XElement node in right.Elements())
{
int num = MergeXml.NodeWithSameNameAtSameHierarchyLevel(left, node);
if (num == 0)
{
left.Add(node);
}
else
{
if (MergeXml.IsFirstIteration(left, right) && !node.HasElements)
{
left.Add(node);
}
else
{
if (num == 1)
{
MergeXml.CheckDescandants(left, node);
}
else
{
if (node.Descendants().Any<XElement>() && node.Descendants().First<XElement>().Name.LocalName.Equals(node.Name.LocalName))
{
MergeXml.CheckDescandants(left, node);
}
else
{
int num2 = node.ElementsBeforeSelf().Count((XElement x) => x.Name.LocalName.Equals(node.Name.LocalName));
foreach (XElement current in node.Elements())
{
if (current.HasElements)
{
if (MergeXml.ItemNodeExistInLeftFile(left, node, num2) || MergeXml.ItemNodeDescandandsDontHaveAnyElements(current))
{
MergeXml.CheckDescandants(left, current, num2);
}
else
{
(
from x in left.Elements()
where x.Name.LocalName.Equals(node.Name.LocalName)
select x).ElementAt(num2).Add(current);
}
}
else
{
(
from x in left.Elements()
where x.Name.LocalName.Equals(node.Name.LocalName)
select x).ElementAt(num2).Add(current);
}
}
}
}
}
}
}
}
public static XDocument MergeXmlFiles(List<XDocument> docs)
{
MergeXml.Merge(docs[0].Root, docs[1].Root);
MergeXml.Merge(docs[0].Root, docs[2].Root);
return docs[0];
}
private static void CheckDescandants(XElement left, XElement node)
{
if (node.Descendants().Count((XElement x) => x.HasElements) > 0)
{
MergeXml.Merge(left.Element(node.Name.LocalName), node);
return;
}
if (left.Element(node.Name.LocalName) != null)
{
if (node.HasElements)
{
left.Element(node.Name.LocalName).Add(node.Descendants());
return;
}
left.Element(node.Name.LocalName).Add(node);
return;
}
else
{
if (node.HasElements)
{
left.Add(node.Descendants());
return;
}
left.Add(node);
return;
}
}
private static void CheckDescandants(XElement left, XElement node, int recursivCallIndex)
{
if (node.Descendants().Count((XElement x) => x.HasElements) > 0)
{
MergeXml.Merge(left.Elements().ElementAt(recursivCallIndex).Element(node.Name.LocalName), node);
return;
}
IEnumerable<XElement> source =
from x in left.Elements().ElementAt(recursivCallIndex).Descendants()
where x.Name == node.Name
select x;
if (source.Count<XElement>() > 0)
{
source.ElementAt(0).Add(node.Descendants());
return;
}
left.Elements().ElementAt(recursivCallIndex).Add(node);
}
private static bool IsFirstIteration(XElement left, XElement right)
{
return left.Parent == null && right.Parent == null;
}
private static bool ItemNodeDescandandsDontHaveAnyElements(XElement item)
{
return item.Descendants().Count((XElement x) => x.HasElements) == 0;
}
private static bool ItemNodeExistInLeftFile(XElement left, XElement node, int positionNodeInXmlIndex)
{
return left.Elements().ElementAt(positionNodeInXmlIndex).Element(node.Name.LocalName) != null;
}
private static int NodeWithSameNameAtSameHierarchyLevel(XElement left, XElement node)
{
if (!left.Descendants().Any<XElement>())
{
return 0;
}
if (left.Descendants().Count((XElement x) => x.Name.LocalName.Equals(node.Name.LocalName)) == 0)
{
return 0;
}
return left.Descendants().Count((XElement x) => x.Name.LocalName.Equals(node.Name.LocalName) && DivideXml.HasSameParentName(x, node));
}

Categories