Finding duplicate properties inside two lists - c#

I have two lists, each list is of type "Node". So I have a StartNodeList and an EndNodeList.
Each Node consists of 3 properties of type Double... X, Y and Z.
The StartNodeList and EndNodeList currently contain Nodes with identical property values.
The output I need is a single list of type Node that contains only Nodes with unique property values (i.e. no duplicate Nodes).
I have tried all manner of foreach loops and comparison operators that I can think of with varying levels of success with nothing working perfectly, and several hours of researching the problem online hasn't helped.
Could someone please help me toward a solution?
while (selector.MoveNext())
{
Beam beam = selector.Current as Beam;
if (beam != null)
{
Node nodeEnd = new Node();
nodeEnd.x = beam.EndPoint.X;
nodeEnd.y = beam.EndPoint.Y;
nodeEnd.z = beam.EndPoint.Z;
Node nodeStart = new Node();
nodeStart.x = beam.StartPoint.X;
nodeStart.y = beam.StartPoint.Y;
nodeStart.z = beam.StartPoint.Z;
Member member = new Member() { member_start = nodeStart, member_end = nodeEnd, member_id = 1 };
memberList.Add(member);
nodeEndList.Add(nodeEnd);
nodeStartList.Add(nodeStart);
memberNumdber++;
}
}
Console.WriteLine(nodeStartList.Count());
Console.ReadLine();
int count = nodeStartList.Count();
foreach(Node i in nodeEndList)
{
nodeListSorted = EqualityComparer.Compare(i, nodeStartList);
}
public static class EqualityComparer
{
public static List<Node> Compare(Node node, List<Node> list)
{
List<Node> output = new List<Node>();
output.Add(node);
foreach(Node i in list)
{
if (node.x.Equals(i.x) && node.y.Equals(i.y) && node.z.Equals(i.z))
{
}
else
{
output.Add(i);
}
}
return output;
}
}

I would recommend using linq. you can use Union which Produces the set union of two sequences and Any which determines whether any element of a sequence exists based onj the given condition.
var uniqueList = list1.Where(el => !list2.Any(l2 => l2.x == el.x && l2.y == el.y && l2.z == e.z)).Union(List2);.ToList();

Related

Trying to sort a list full of a object by the a list from that object's properties c#

I have a class that has a bunch of different variables and a couple lists 1 in particular holds ints(positionInts)
I also have a list(teamsList) for holding objects I have created from that class
now I would like to sort the team's list by positions values
Hopefully, I'm not being too vague as the project I'm working on is full of not well-written code so it can be hard to explain.
This function orders the list according to your precondition.
private List<String> OrderList(List<String> teams, int[] positions)
{
List<String> orderedTeams;
Dictionary<int, string> teamsToOrder = new Dictionary<int, string>();
int position = 0;
foreach (string team in teams)
{
teamsToOrder.Add(positions[position], teams[position]);
position = position + 1;
}
orderedTeams = teamsToOrder.OrderByDescending(team => team.Key).Select(team => team.Value).ToList();
return orderedTeams;
}
If I understand your question correctly, then you have list of arbitrary type, for example list of strings:
var teamsList = new List<String> { "team1", "team2", "team3", "team4" };
Next up, you have enumeration of integers:
var positionInts = new[] { 2, 3, 1, 0 };
And your goal is to order teamsList based on sequence numbers of the positionInts. In that case you can use following method:
static IEnumerable<T> OrderBySequence<T>(IEnumerable<T> source, IEnumerable<Int32> sequence)
{
for (var i = 0; i < Math.Min(source.Count(), sequence.Count()); i++)
{
var s = sequence.ElementAt(i);
if (s > -1 && s < source.Count())
{
yield return source.ElementAt(s);
}
}
}
Which will produce:
team3
team4
team2
team1

Function list variable doesn't return the current state of a recursive variable

I am working with a graph data structure and have a recursive function to calculate the depth of a node by counting the parents to the root node.
There are some other issues that I need to deal with, but for right now my main problem is to do with storing the current value of the recursive dictionary parameter, which stores the path branches.
using System;
using System.Collections.Generic;
using System.Linq;
public class Node {
public string name;
public int ID;
public int maxDepth;
public readonly List<Node> Dependencies = new List<Node>();
public readonly List<Node> Children = new List<Node>();
public bool isOrphan {
get {
return Dependencies.Count == 0;
}
}
public bool isParent {
get {
return Children.Count != 0;
}
}
}
public class test {
private static readonly List<Node> nodes = new List<Node>();
public static void Main() {
Node A = new Node() {
name = "A",
ID = 1
};
Node B = new Node() {
name = "B",
ID = 2
};
Node C = new Node() {
name = "C",
ID = 3
};
Node D = new Node() {
name = "D",
ID = 4
};
Node E = new Node() {
name = "E",
ID = 5
};
Node F = new Node() {
name = "F",
ID = 6
};
Node G = new Node() {
name = "G",
ID = 7
};
nodes.Add(A);
nodes.Add(B);
nodes.Add(C);
nodes.Add(D);
nodes.Add(E);
nodes.Add(F);
nodes.Add(G);
A.Children.Add(B);
A.Children.Add(G);
B.Children.Add(C);
B.Children.Add(D);
C.Children.Add(D);
D.Children.Add(E);
E.Children.Add(F);
B.Dependencies.Add(A);
C.Dependencies.Add(B);
D.Dependencies.Add(B);
D.Dependencies.Add(C);
E.Dependencies.Add(D);
E.Dependencies.Add(G);
F.Dependencies.Add(E);
G.Dependencies.Add(A);
foreach (Node n in nodes) {
n.maxDepth = getMaxNodeDepth(n);
}
Console.ReadLine();
}
private static int getMaxNodeDepth(Node n, string listIndex = "base",
Dictionary<string, List<int>> paths = null) {
bool firstIteration = false;
if (paths == null) {
firstIteration = true;
listIndex = n.name.Replace(" ", "-");
paths = new Dictionary<string, List<int>> {
{listIndex, new List<int>(0)}
};
}
// Prevent the starting node from being added to the path
if (!paths[listIndex].Contains(n.ID) && !firstIteration)
paths[listIndex].Add(n.ID);
// This variable should take the CURRENT path and store it;
// not the value after all the recursion has completed.
// Right now, the current path is affected by the recursions, somehow...
List<int> currentPath = new List<int>(paths[listIndex]);
foreach (Node parent in n.Dependencies) {
if (n.Dependencies.Count >= 2) {
listIndex = parent.name;
paths.Add(listIndex, currentPath);
}
getMaxNodeDepth(parent, listIndex, paths);
}
// Print out branches
if (firstIteration) {
string list = n.name + "\n";
int listNumber = 1;
foreach (List<int> iList in paths.Values) {
list += string.Format("Branch#{0} -- ", paths.Keys.ElementAt(listNumber - 1));
int total = 0;
foreach (int i in iList) {
list += string.Format("{0}, ", nodes.First(x => x.ID == i).name);
total++;
}
listNumber++;
list += string.Format(" -- ({0})\n", total);
}
Console.WriteLine(list);
}
// Order all paths by length, return the highest count
// This is to be used to space out the hierarchy properly
return paths.Values.OrderByDescending(path => path.Count).First().Count;
}
}
When the foreach loop encounters a node with more than one parent, it creates a new branch and should populate it with the current IDs of the nodes.
C D
\ /
B
|
A
|
...
What should happen
Using the above example, beginning with A, it will first iterate B, as its direct parent. Then it begins on B's parents, which it has two of and because of this, it creates a separate branch and should fill that branch with B and its children (until the starting node, this time being A).
What actually does
Somehow, when B has finished iterating over C, parent D polls the current path and is returned B, C, where it should actually be just B, as C is a sibling, not a direct child or parent.
Huge edit
The code I've attached runs completely out of the box and contains an example. You can see the result contains some anomalous results, such as
F
Branch#G -- E, D, G, A, -- (4)
which should actually be
G
Branch#G -- G, A, -- (2)
When you give a dictionary as a parameter to a method, the contents of the dictionary is not copied, only the reference to the dictionary is copied.
So altering the dictionary in one recursion branch will change the dictionary for the other branch as well.
To fix it, you can copy the dictionary explicitly yourself when passing the dictionary:
getMaxNodeDepth(parent, listIndex, new Dictionary<string, List<int>>(paths));
EDIT: Actually that wouldn't be enough either since it will copy the reference to the inner list and not the contents of the inner list, so you'll need a more nested cloning code:
private Dictionary<string, List<int>> clone(Dictionary<string, List<int>> map)
{
Dictionary<string, List<int>> clone = new Dictionary<string, List<int>>(map.Count);
foreach (var pair in map)
{
clone[pair.Key] = new List<int>(pair.Value);
}
return clone;
}
//And then call it from your code:
getMaxNodeDepth(parent, listIndex, clone(paths));
However, assuming you don't need to fill this paths dictionary for outside code, and the only output here is the "maximum depth" of the node, you can probably simplify your code a lot, for example:
private int getMaxNodeDepth(Node n)
{
if (n.Dependencies == null || n.Dependencies.Count == 0) return 1;
return 1 + n.Dependencies.Max(parent => getMaxNodeDepth(parent));
}
EDIT: edited to add a solution that returns the "maximum path" as well:
private List<Node> getMaxNodeDepth(Node n)
{
List<Node> path =
n.GetSubFolders().Select(getMaxNodeDepth).OrderByDescending(p => p.Count).
FirstOrDefault() ?? new List<Node>();
path.Insert(0, n);
return path;
}
EDIT: and based on the comment from the OP, here's a solution that returns all available paths:
private static List<List<Node>> getAllPaths(Node n)
{
if (n.Dependencies == null || n.Dependencies.Count == 0)
return new List<List<Node>> { new List<Node> { n }};
List<List<Node>> allPaths = n.Dependencies.SelectMany(getAllPaths).ToList();
allPaths.ForEach(path => path.Insert(0, n));
return allPaths;
}
private static int getMaxDepth(Node n)
{
return getAllPaths(n).Max(p => p.Count);
}

parsing xsd complexType recursively

private ElementDefinition ParseComplexType(XElement complexType, string nameValue = "")
{
var name = complexType.Attribute("name");
ElementDefinition element = new ElementDefinition()
{
Elements = new List<ElementDefinition>(),
ElementName = name != null ? name.Value : string.Empty
};
foreach (var el in complexType.Descendants().Where(k => k.Parent.Parent == complexType && k.Name.LocalName == "element"))
{
ElementDefinition tempElement = new ElementDefinition();
var tempName = el.Attribute("name");
var tempType = el.Attribute("type");
if (tempName != null)
{
tempElement.ElementName = tempName.Value;
}
if (tempType != null)
{
var tempTypeValue = tempType.Value.Substring(tempType.Value.IndexOf(":") + 1, tempType.Value.Length - tempType.Value.IndexOf(":") - 1);
if (tipovi.Contains(tempTypeValue))
{
tempElement.ElementType = tempTypeValue;
element.Elements.Add(tempElement);
}
else
{
complexType = GetComplexType(tempTypeValue);
element.Elements.Add(ParseComplexType(complexType, tempName.Value));
}
}
}
if (nameValue != "") element.ElementName = nameValue;
return element;
}
Hi so this is a function i use for parsing XSD complexTypes.
This is a xsd schema i use xsd Schema.
I have problem parsing complexType element at line 14.
It only parses shipTo element, skipping billTo and parsing badly items.
The result is http://pokit.org/get/?b335243094f635f129a8bc74571c8bf2.jpg
Which fixes can i apply to this function in order to work properly?
PS. "tipovi" is list of xsd supported types, e.g. string, positiveInteger....
EDITED:
private XElement GetComplexType(string typeName)
{
XNamespace ns = "http://www.w3.org/2001/XMLSchema";
string x = "";
foreach (XElement ele in xsdSchema.Descendants())
{
if (ele.Name.LocalName == "complexType" && ele.Attribute("name") != null)
{
x = ele.Attribute("name").Value;
if (x == typeName)
{
return ele;
}
}
}
return null;
}
GetComplexType finds complexType definition of an element type. For example, for "PurchaseOrderType" (line 10) it returns element at line 14.
NOTE: This is only a partial answer as it only explains the issue regarding the skipped "billTo" element. The code as presented in the question has many more issues.
The problem regarding skipping of the billTo element
The complexType variable is used in the predicate for the Linq method Where in the foreach loop:
complexType.Descendants().Where(k => k.Parent.Parent == complexType && k.Name.LocalName == "element"))
This lambda expression uses the variable complexType, not merely its value.
By assigning another value to complexType deep down inside your foreach loop
complexType = GetComplexType(tempTypeValue);
you also change the logic of which elements are filtered by the predicate of the Where method in the the foreach loop.
The Fix
The solution is rather simple: Do not change the complexType variable within the foreach loop. You could do the call of GetComplexType like this:
XElement complexTypeUsedByElement = GetComplexType(tempTypeValue);
element.Elements.Add(ParseComplexType(complexTypeUsedByElement, tempName.Value));

How to improve code to set the depth of a traverse tree in a C# datatable? [duplicate]

This question already has an answer here:
How to validate if a parent item has children in recursive LINQ function?
(1 answer)
Closed 9 years ago.
I have a datatable that has a traverse tree structure on it, it has lots of columns but the ones that matter are as follows:
|RepID|LeaderID|Depth|
I want to set the tree's depth as:
RepID that has no LeaderID (null) should be depth 0
RepID that has as a leader the ones that have depth 0 should be depth 1 and so on
Up to now I made a recursive algorithm that is getting the job done, however since I'm iterating over 400,000 rows it's taking a lot of time.
Up to now my code is as follows:
public static DataTable SetTreeLevel(DataTable dtReps)
{
//Getting the 1st level (reps without a leader)
var first_level = from r in dtReps.AsEnumerable()
where (r.Field<int?>("LeaderID") == null || r.Field<int?>("LeaderID") == 0)
select r;
//Setting the level for the reps obtained
foreach (var row in first_level)
{
row["Depth"] = 1;
}
//Setting the next levels
return setTreeLevelRecursive(dtReps, 2);
}
private static DataTable setTreeLevelRecursive(DataTable dtReps, int depth)
{
//Getting reps of the last level (depth -1)
var last_level = from r in dtReps.AsEnumerable()
where r.Field<int?>("Depth") == depth - 1
select r.Field<int?>("RepID");
//List to improve performance
List<int?> last_level_list = last_level.ToList<int?>();
//Getting the next level reps (leader is on the last level list)
var actual_level = from r in dtReps.AsEnumerable()
where last_level_list.Contains(r.Field<int?>("LeaderID"))
select r;
//List to improve performance
List<DataRow> actual_level_list = actual_level.ToList<DataRow>();
foreach (DataRow row in actual_level_list)
{
row["Depth"] = depth;
}
//Validating if there are reps without depth
if ((from r in dtReps.AsEnumerable()
where r.Field<int?>("Depth") == null
select r).Count() > 0)
{
//Asignando siguiente nivel
setTreeLevelRecursive(dtReps, depth + 1);
}
//Regresando resultado
return dtReps;
}
Edit: Using Servy's optimization I coded the following:
var lookup = dtReps.AsEnumerable().ToLookup(x => x.Field<int?>("LeaderID"));
//First level
var first_level = from r in dtReps.AsEnumerable()
where (r.Field<int?>("LeaderID") == null || r.Field<int?>("LeaderID") == 0)
select Tuple.Create(r.Field<int>("RepID"), 1);
var rows = Traverse(first_level, node => lookup[node.Item1]
.Select(row => Tuple.Create(row.Field<int>("RepID"), node.Item2 + 1))).ToList();
foreach (var r in rows)
{
(from r_nivel in dtReps.AsEnumerable()
where r_nivel.Field<int>("RepID") == r.Item1
select r_nivel).FirstOrDefault()["Depth"] = r.Item2;
}
But the foreach takes a lot of time
Thanks!
First, you can define a Rep object:
public class Rep
{
public int RepID {get;set;}
public int LeaderID {get;set;}
public int Depth {get;set;}
}
Then you populate a List from your DataTable using:
List<Rep> Reps=dtReps.OfType<DataRow>().Select(c=>new Rep(){RepID=Convert.ToInt32(c["RepID"]),LeaderID=Convert.ToInt32(c["LeaderID"])).ToList();
Then you create a lookup table for each leader's reps by:
Dictionary<int,List<Rep>> LeaderLookup=Reps.GroupBy(c=>c.LeaderID).ToDictionary(c=>c.Key,c=>c.ToList());
Now you use LeaderLookup to recursively set Depths. This is very fast, I am using similar data with around 3,000 items, and it can be populate under a second.
To do that, you define this function:
private void RecursivelySetDepthOfChildren(int RepID,int CurrentDepth,Dictionary<int,<List<Rep>> LeaderLookup)
{
int DepthOfChildren=CurrentDepth+1;
foreach(Rep child in LeaderLookup[RepID])
{
child.Depth=DepthOfChildren;
RecursivelySetDepthOfChildren(child.RepID,child.Depth,LeaderLookup);
}
}
Then you invoke the function with:
RecursivelySetDepthOfChildren(0,0,LeaderLookup);
after the ToDictionary statement. After that call completes you will have a List with depths all set correctly. You can iterate through that to save it to the Database.
How long does that take?

Group pairs of connected values into Lists

So I am working on a problem, and coming up against a wall that I can't seem to find a way around. I get so much information from OS, that I thought I would ask on here, and see if there is a way to do this better than what I'm finding.
Basically, I have a class that has a bunch of values in it, but for our purposes only one matters.
public class GroupPair
{
public string object1 { get; set; }
public string object2 { get; set; }
public List<string> BothObjects
{
get
{
List<string> s= new List<string>();
s.Add(object1);
s.Add(object2);
return s;
}
}
I have a List, and I need to be able to sort them into groups. Where it becomes tricky is that both values are not unique, and the group size and number of groups is variable. I basically need a way to say, "give me every group that can be made from this list, where each group contains all pairs that include any individual member of the group." Let me give and example... here are some pairs:
a d
f h
d t
n w
h a
n o
q d
w f
o y
After the grouping, this is what I want:
Group 1
a d
h a
q d
f h
w f
d t
Group 2
n x
n o
o y
Melt your brain yet?
Any ideas on how this could be done, or even if there is a name for this kind of concept that I can research myself?
Here's my quick-and-dirty approach.
Short explanation:
The idea is to start with one pair (which can be thought of as a node in a graph). From that node, you add any adjacent nodes (pairs which have a shared member). Then you search the nodes adjacent to those nodes that you just added. All along you keep track of which nodes have been visited so you don't loop endlessly.
public static List<HashSet<GroupPair>> GetGroups(IEnumerable<GroupPair> pairs)
{
var groups = new List<HashSet<GroupPair>();
var unassignedPairs = new HashSet<GroupPair>(pairs);
while (unassignedPairs.Count != 0)
{
var group = new HashSet<GroupPair>();
var rootPair = unassignedPairs.First();
group.Add(rootPair);
unassignedPairs.Remove(rootPair);
var membersToVisit = new Queue<string>(rootPair.BothObjects);
var visited = new HashSet<string>();
while (members.Count != 0)
{
string member = membersToVisit.Dequeue();
visited.Add(member);
foreach (var newPair in unassignedPairs
.Where(p => p.BothObjects.Contains(member)).ToList())
{
group.Add(newPair);
unAssignedPairs.Remove(newPair);
foreach (var newMember in newPair.BothObjects.Except(visited))
{
membersToVisit.Enqueue(newMember)
}
}
}
groups.Add(group);
}
return groups;
}
This is just an idea for a solution.
You'll need to know how many unique 'individuals' you have. For your example, it's 26.
First, you create a dictionary of 26 pairs, where key is an individual, in our case a letter, and a value is a group number where it will be in the end. For each pair, initial value should be zero.
Second, you keep a 'groupNumber' integer variable that will store the next group number. You initialise it with 1.
Then, you iterate over the list of GroupPairs. You take the first GroupPair, which contains 'a' and 'd' and set the respective values in the dictionary to '1'.
For each following GroupPair you take its individuals and look up the respective values in the dictionary.
If one of the values is non-zero, i.e. one of the individuals already belongs to a group, you set the other value to the same number, thus putting it in the same group.
If both values are zeros you set them to 'groupNumber' and increment 'groupNumber'.
If both values are non-zero, this is where it gets a bit tricky. You find all pairs in the group dictionary where value equals the second value from that pair, and set their value to the first value from that pair.
After that is done, you iterate over the list of GroupPairs once again. For each pair you look up the first individual in the group dictionary and thus find out which group the pair belongs to.
Hope that makes sense...
This code matches the sample input and produces the required output. Bascially I keep a HashSet of items per group and have list of remaing items to process.
private static void GroupPairs(List<Tuple<string, string>> pairs)
{
int groupCounter = 0;
while (pairs.Count > 0)
{
var onegroup = new HashSet<string>();
Console.WriteLine("Group {0}", ++groupCounter);
int initialGroupCount;
do
{
var remainder = new List<Tuple<string, string>>();
initialGroupCount = onegroup.Count;
foreach (var curr in pairs)
{
if (onegroup.Contains(curr.Item1) ||
onegroup.Contains((curr.Item2)) ||
onegroup.Count == 0)
{
Console.WriteLine("{0} {1}", curr.Item1, curr.Item2);
onegroup.Add(curr.Item1);
onegroup.Add(curr.Item2);
}
else
{
remainder.Add(curr);
}
}
pairs = remainder;
} while (initialGroupCount < onegroup.Count);
}
}
For the sake of completeness I also have a recursive solution.
Near the end is the GroupPair class that acts as datacontainer with two helper methods: Add and Merge.
You invoke it like so:
var gp = GroupByPairs(
new List<Tuple<string, string>>
{
new Tuple<string, string>("a", "d"),
new Tuple<string, string>("f", "h"),
/* you get the idea */
}.GetEnumerator());
foreach (var groupData in gp)
{
Console.WriteLine(groupData.ToString());
}
//recursive take on the problem
private static IEnumerable<GroupPair> GroupByPairs(
IEnumerator<Tuple<string, string>> pairs)
{
// result Groups
var listGroup = new List<GroupPair>();
if (pairs.MoveNext())
{
var item = pairs.Current;
var current = new GroupPair(item);
var subgroup = GroupByPairs(pairs); // recurse
// loop over the groups
GroupPair target = null;
foreach (var groupData in subgroup)
{
// find the group the current item matches
if (groupData.Keys.Contains(item.Item1) ||
groupData.Keys.Contains(item.Item2))
{
// determine if we already have a target
if (target == null)
{
// add item and keep groupData
target = groupData;
groupData.Add(item);
listGroup.Add(groupData);
}
else
{
// merge this with target
// do not keep groupData
target.Merge(groupData);
}
}
else
{
// keep groupData
listGroup.Add(groupData);
}
}
// current item not added
// store its group in the listGroup
if (target == null)
{
listGroup.Add(current);
}
}
return listGroup;
}
public class GroupPair
{
private static int _groupsCount = 0;
private int id;
public GroupPair(Tuple<string, string> item)
{
id = Interlocked.Increment(ref _groupsCount);
Keys = new HashSet<string>();
Items = new List<Tuple<string, string>>();
Add(item);
}
// add the pair and update the Keys
public void Add(Tuple<string, string> item)
{
Keys.Add(item.Item1);
Keys.Add(item.Item2);
Items.Add(item);
}
// Add all items from another GroupPair
public void Merge(GroupPair groupPair)
{
foreach (var item in groupPair.Items)
{
Add(item);
}
}
public HashSet<string> Keys { get; private set; }
public List<Tuple<string, string>> Items { get; private set; }
public override string ToString()
{
var build = new StringBuilder();
build.AppendFormat("Group {0}", id);
build.AppendLine();
foreach (var pair in Items)
{
build.AppendFormat("{0} {1}", pair.Item1, pair.Item2);
build.AppendLine();
}
return build.ToString();
}
}

Categories

Resources