Partition graph by connection degree - c#

I would to ask if there is already algorithms for graphs that partition graphs into subgraphs like the screenshot attached:
Graph has edges
A-B,B-C,C-D, D-E, C-F, F-G
I need to partition it to 3 parts since vertex C has degree of 3:
A-B-C
C-D-E
C-F-G
First I was thinking that I can remove C node and disconnect graph using typical methods. But maybe there already known method to partition graphs by nodes degree?

I wrote a simple algorithm for this. Please note that the graph is needed to be ordered
public static void Main()
{
Console.WriteLine("Hello World");
var str = "A-B,B-C,C-D,D-E,C-F,F-G";
var resultSet = Graph(str.Split(','), '-');
}
public static string[] Graph(string[] s, char delimiter)
{
var resultSet = new List<string>();
var prevOperLeft = "";
var prevOperRight = "";
foreach (var part in s)
{
var oper = part.Split(delimiter);
var left = oper[0];
var right = oper[1];
if (prevOperRight == left)
{
resultSet.Add(string.Format("{0}{1}{2}{3}{4}", prevOperLeft, delimiter, left, delimiter, right));
prevOperLeft = prevOperRight = "";
}
else
{
prevOperLeft = left;
prevOperRight = right;
}
}
return resultSet.ToArray();
}
https://dotnetfiddle.net/e3kmpR
More generic example with LinkedList
public static IList<LinkedList<T>> Graph2<T>(LinkedList<T> ll) where T: class
{
var resultSet = new List<LinkedList<T>>();
T prevOperLeft = null;
T prevOperRight = null;
while (ll.Count > 0)
{
var left = ll.First.Value;
ll.RemoveFirst();
var right = ll.First.Value;
ll.RemoveFirst();
if (prevOperRight != null && prevOperRight.Equals(left))
{
resultSet.Add(new LinkedList<T>(new []{ prevOperLeft, left, right }));
prevOperLeft = prevOperRight = null;
}
else
{
prevOperLeft = left;
prevOperRight = right;
}
}
return resultSet;
}
public static void Main()
{
var A = new MyClass {Name = "A"};
var B = new MyClass {Name = "B"};
var C = new MyClass {Name = "C"};
var D = new MyClass {Name = "D"};
var E = new MyClass {Name = "E"};
var F = new MyClass {Name = "F"};
var G = new MyClass {Name = "G"};
List<MyClass> list = new List<MyClass>
{
A,B,B,C,C,D,D,E,C,F,F,G
};
LinkedList<MyClass> ll = new LinkedList<MyClass>(list);
var resultSet2 = Graph2(ll);
}
class MyClass
{
public string Name { get; set; }
}

Related

How to get intersection of two classes based on property

I have this class
public class FlightSegment{
public string ClassName { get;set;}
}
And I want to get FlightSegments with common ClassName
void Main()
{
var list1 = new List<FlightSegment>() {
new FlightSegment{ ClassName = "A"},
new FlightSegment { ClassName = "B"}
};
var list2 = new List<FlightSegment>() {
new FlightSegment{ ClassName = "B"},
new FlightSegment { ClassName = "C"}
};
var listOfLists = new List<List<FlightSegment>>() { list1, list2 };
var intersection = listOfLists.Aggregate((previousList, nextList) => previousList.Intersect(nextList).ToList());
Console.WriteLine(intersection); //Gives me empty result
}
I tried something like this:
var intersection = listOfLists.Aggregate((previousList, nextList) =>
previousList.Select(e=>e.ClassName).Intersect(nextList.Select(e=>e.ClassName)).ToList());
But gives error:
Cannot convert expression type System.Collection.Generic.List<string> to return type System.Collection.Generic.List<FlightSegment>
You can use Intersect method passing a IEqualityComparer to compare according to ClassName property:
class FlightComparer : EqualityComparer<FlightSegment>
{
public override bool Equals(FlightSegment x, FlightSegment y)
{
return x.ClassName == y.ClassName;
}
public override int GetHashCode(FlightSegment obj)
{
return obj.ClassName.GetHashCode();
}
}
Then, make the intersection using this comparer:
var list1 = new List<FlightSegment>() {
new FlightSegment{ ClassName = "A"},
new FlightSegment { ClassName = "B"}
};
var list2 = new List<FlightSegment>() {
new FlightSegment{ ClassName = "B"},
new FlightSegment { ClassName = "C"}
};
var result = list1.Intersect(list2, new FlightComparer());
This returns a collection containing only one element FlightSegment { ClassName = "B" }.
Using this idea and Aggregate, you can get the intersection of a group of lists based on a property:
var intersection = listOfLists.Aggregate((previousList, nextList) => previousList.Intersect(nextList, new FlightComparer() ).ToList());

Use list<int> as a linq group by key

This is from LinqPad (hence the .Dump())
void Main()
{
var k1 = new List<int>(){1,2,3,4,5};
var k2 = new List<int>(){1,2,3,4,5};
var o1 = new A(){k=k1, objectName="o1"};
var o2 = new A(){k=k2, objectName="o2"};
var l = new List<A>();
l.Add(o1);
l.Add(o2);
var b = from a in l
group a.objectName by a.k into g
select new {g.Key, n = String.Join(",",g)};
b.Dump();
}
public class A {
public List<int> k;
public string objectName;
}
The problem is that it doesn't work, the code above yields:
I know why this is happening, it's because the list objects are separate objects, but what I was wondering is if there is a way to tell group by to use content of the list rather than the object instance.
public static void Main()
{
var k1 = new List<int>(){1,2,3,4,5};
var k2 = new List<int>(){1,2,3,4,5};
var o1 = new A(){k=k1, objectName="o1"};
var o2 = new A(){k=k2, objectName="o2"};
var l = new List<A>();
l.Add(o1);
l.Add(o2);
// Use custom comparer for the list
var b = l.GroupBy(a => a.k, new ListComparer<int>())
.Select(g => new
{
Key = String.Join(",", g.Key.Select(i => i)),
n = String.Join(",",g.Select(i => i.objectName))
});
foreach(var item in b)
{
Console.WriteLine(string.Format("{0} : {1}", item.Key, item.n));
// 1,2,3,4,5 : o1,o2
}
}
public class A
{
public List<int> k;
public string objectName;
}
public class ListComparer<T> : IEqualityComparer<List<T>>
{
// Ignore the order and compare with the sequence value for the equality
public bool Equals(List<T> left, List<T> right)
{
return left.OrderBy(i => i).SequenceEqual(right.OrderBy(i => i));
}
public int GetHashCode(List<T> list)
{
return list.Count;
}
}
.Net Fiddle
You can convert array to string.
var b = l.GroupBy(o => string.Join(";", o.k))
.Select(g => new { Key = g.First().k,
n = string.Join(",", g.Select(o => o.objectName)) });
I managed to accomplish the following:
var b = l.SelectMany(a => a.k.Select(i => new { Key = i, n = a.objectName }))
.GroupBy(i => i.Key);

Why am I not getting results when performing an intersection?

Users class:
public class User
{
public int ID { get; set; }
public string Email { get; set; }
}
Code:
var usersL = new List<User>()
{
new User{ID = 1,Email = "abc#foo.com"},
new User{ID = 2,Email = "def#foo.com"}
};
var usersR = new List<User>()
{
new User{ID = 1,Email = "abc#foo.com"},
new User{ID = 2,Email = "def#foo.com"}
};
var both = (from l in usersL select l)
.Intersect(from users in usersR select users);
foreach (var r in both)
Console.WriteLine(r.Email);
Which returns 0 results.
I know I can accomplish something similar by using join, but I want to use Intersect because A) this is eventually going to work on some DB code and we want to use this function (too long to go into why) and B) I'm just plain curious as to why Intersect isn't working here.
var both = from l in usersL
join r in usersR on l.ID equals r.ID
select l;
.Net provides comparison logic for predefined types. In case of your join query your were joining (comparing) two IDs which were of type Int (predefined types)
var both = from l in usersL
join r in usersR on l.ID equals r.ID
select l;
In case of your intersect query you are trying to compare two user defined custom objects of type User. Hence you need to provide your own custom compare implementation logic.
There are 2 ways to tackle this...
Option 1:
Implement the IEqualityComparer
public class User
{
public int ID { get; set; }
public string Email { get; set; }
}
public class MyEqualityComparer : IEqualityComparer<User>
{
public bool Equals(User x, User y)
{
if (object.ReferenceEquals(x, y))
return true;
if (x == null || y == null)
return false;
return x.ID.Equals(y.ID) &&
x.Email.Equals(y.Email);
}
public int GetHashCode(User u)
{
return new { u.ID, u.Email }.GetHashCode();
}
}
class Program
{
static void Main(string[] args)
{
var usersL = new List<User>()
{
new User{ID = 1,Email = "abc#foo.com"},
new User{ID = 2,Email = "def#foo.com"}
};
var usersR = new List<User>()
{
new User{ID = 1,Email = "abc#foo.com"},
new User{ID = 2,Email = "def#foo.com"}
};
var both = (from l in usersL select l)
.Intersect(from users in usersR select users, new MyEqualityComparer());
foreach (var r in both)
Console.WriteLine(r.Email);
}
}
Option 2: Override the Equals and GetHashcode methods in the custom object itself
public class User
{
public int ID { get; set; }
public string Email { get; set; }
public override bool Equals(Object obj)
{
// Check for null values and compare run-time types.
if (obj == null || GetType() != obj.GetType())
return false;
User x = (User)obj;
return (ID == x.ID) && (Email == x.Email);
}
public override int GetHashCode()
{
return new { ID, Email }.GetHashCode();
}
}
class Program
{
static void Main(string[] args)
{
var usersL = new List<User>()
{
new User{ID = 1,Email = "abc#foo.com"},
new User{ID = 2,Email = "def#foo.com"}
};
var usersR = new List<User>()
{
new User{ID = 1,Email = "abc#foo.com"},
new User{ID = 2,Email = "def#foo.com"}
};
var both = (from l in usersL select l)
.Intersect(from users in usersR select users);
foreach (var r in both)
Console.WriteLine(r.Email);
}
}
Hope this helps.
This is in response to #sundeep who said "Now regards to your 2nd question... " (I wish you could link to comments) -- I'm just creating a new answer as I don't want to ruin the context of my original question
User class implementing IEqualityComparer
public class User : IEqualityComparer<User>
{
public int ID { get; set; }
public string Email { get; set; }
public bool Equals(User x, User y)
{
if (object.ReferenceEquals(x, y))
return true;
if (x == null || y == null)
return false;
return x.ID.Equals(y.ID) &&
x.Email.Equals(y.Email);
}
public int GetHashCode(User obj)
{
return new { obj.ID, obj.Email }.GetHashCode();
}
}
Intersection returns no rows:
var usersL = new List<User>()
{
new User{ID = 1,Email = "abc#foo.com"},
new User{ID = 2,Email = "def#foo.com"}
};
var usersR = new List<User>()
{
new User{ID = 1,Email = "abc#foo.com"},
new User{ID = 2,Email = "def#foo.com"}
};
var both = (from l in usersL select l)
.Intersect(from users in usersR select users);
foreach (var r in both)
Console.WriteLine(r.Email);

How to invoke a another method in main() method to display one array grouped under second one

I want to create 3 methods, 2 to declare and initialize arrays. And 3rd to loop through the 2 arrays. I want to invoke the third method in main() to display each index of array2 grouped under array1 index. I hope I have put my question through clearly.
class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.display(Carnivore, ZooMammals);
}
public void Mammals(ZooMammals[] category)
{
category = new ZooMammals[4];
category[1] = new ZooMammals() {Category="Carnivorous", Attribute = new Attributes[2] };
category[2] = new ZooMammals() { Category = "Carnivorous", Attribute= new Attributes[1] };
category[3] = new ZooMammals() { Category = "Carnivorous", Attribute = new Attributes[3] };
}
public static void Carnivore(Attributes[] Carn)
{
Carn = new Attributes[3];
Carn[0] = new Attributes() { Sex ="M", colour = "yellow",Name="Lion" };
Carn[1] = new Attributes() { Sex ="F", colour = "yellow",Name="Cat"};
Carn[2] = new Attributes() { Sex ="M", colour = "yellow",Name="Tiger"};
}
public static void display(Attributes[] Carn,ZooMammals[] category)
{
foreach (var a in category)
{
if (a == null) continue;
Console.WriteLine("{0},{1},{2}", a.Category, a.Attribute);
}
foreach (var x in category.Carn)
{
if (x == null) continue;
Console.WriteLine("{0},{1},{2}", x.Sex, a.colour, x.Name);
Console.WriteLine(category[1].Carn[0]);
Console.WriteLine(category[1].Carn[1]);
Console.WriteLine(category[1].Carn[2]);
Console.WriteLine(category[2].Carn[0]);
Console.WriteLine(category[2].Carn[1]);
}
Console.ReadLine();
}
}
public class Attributes
{
public string Sex;
public string colour;
public string Name;
}
public class ZooMammals
{
public string Category;
public Attributes[] Attribute;
}
}
static void Main(string[] args)
{
Program p = new Program();
p.display(Mammals(), Carnivore());
}
public ZooMammals[] Mammals()
{
ZooMammals[] category = new ZooMammals[4];
category[1] = new ZooMammals() {Category="Carnivorous", Attribute = new Attributes[2] };
category[2] = new ZooMammals() { Category = "Carnivorous", Attribute= new Attributes[1] };
category[3] = new ZooMammals() { Category = "Carnivorous", Attribute = new Attributes[3] };
return category;
}
public Attributes[] Carnivore()
{
Attributes[] Carn = new Attributes[3];
Carn[0] = new Attributes() { Sex ="M", colour = "yellow",Name="Lion" };
Carn[1] = new Attributes() { Sex ="F", colour = "yellow",Name="Cat"};
Carn[2] = new Attributes() { Sex ="M", colour = "yellow",Name="Tiger"};
return Carn;
}
This is where you are going wrong i feel. This can be done better by declaring two global arrays and just assigning values in the methods and using the same through out the code.

yield return returning same result on each iteration

The problem is to generate combinations of search parameters to be used as test case inputs in automation tests.
public class CombinationInput<T>
{
public string Name { get; set; }
public List<T> PossibleValues { get; set; }
public bool ReadOnly { get; set; }
}
GetCombinations is a method in the Combinationsgenerator Class:
private IEnumerable<object[]> _GetCombinations(ArrayList inputs)
{
var returnobjects = new object[inputs.Count];
var element = inputs[0];
var type = element.GetType();
var generictype = type.GenericTypeArguments[0];
var elementvalues = type.GetProperty("PossibleValues").GetValue(element, null) as IEnumerable;
foreach (var val in elementvalues)
{
returnobjects[0] = val;
if (inputs.Count > 1)
{
var objs = _GetCombinations(inputs.GetRange(1, inputs.Count - 1));
foreach (var item in objs)
{
for (int i = 0; i < item.Length; i++)
{
returnobjects[i + 1] = item[i];
}
yield return returnobjects;
}
}
else
{
yield return returnobjects;
}
}
}
Inside TestMethod:
[TestMethod]
public void GetCombinationTest()
{
var x = new CombinationInput<Enums.AmountType>();
var y = new CombinationInput<Enums.AreaMeasureType>();
var z = new CombinationInput<Enums.DisplayItemType>();
ArrayList list = new ArrayList();
list.Add(x);
list.Add(y);
list.Add(z);
var combgen = new CombinationGenerator(list);
var combs = combgen.GetCombinations();
}
Get Combinations is always returning the same combination when I run the code but when I debug through the code each time it hits the yield return statement its having the right combination.
You always return the same object as you are editing the content itself. What you are yielding is the reference to an array, and it's always the same reference. Instead of reusing the same array, you should move the declaration and creation of returnobjects within the foreach loop.

Categories