How to implement a equality method? - c#

Given the examples below, how would I make clientList contain 5 clients in the second example?
I want the list.Contains() method only check the FName and LName strings and disregard the age when checking for equality.
struct client
{
public string FName{get;set;}
public string LName{get;set;}
public int age{get;set;}
}
Example 1:
List<client> clientList = new List<client>();
for (int i = 0; i < 5; i++)
{
client c = new client();
c.FName = "John";
c.LName = "Smith";
c.age = 10;
if (!clientList.Contains(c))
{
clientList.Add(c);
}
}
//clientList.Count(); = 1
Example 2:
List<client> clientList = new List<client>();
for (int i = 0; i < 5; i++)
{
client c = new client();
c.FName = "John";
c.LName = "Smith";
c.age = i;
if (!clientList.Contains(c))
{
clientList.Add(c);
}
}
//clientList.Count(); = 5

Create a Class which implements IEqualityComparer , and pass the object in list.contains method

public class Client : IEquatable<Client>
{
public string PropertyToCompare;
public bool Equals(Client other)
{
return other.PropertyToCompare == this.PropertyToCompare;
}
}

Override Equals and GetHashCode in your structure:
struct client
{
public string FName { get; set; }
public string LName { get; set; }
public int age { get; set; }
public override bool Equals(object obj)
{
if (obj == null || !(obj is client))
return false;
client c = (client)obj;
return
(string.Compare(FName, c.FName) == 0) &&
(string.Compare(LName, c.LName) == 0);
}
public override int GetHashCode()
{
if (FName == null)
{
if (LName == null)
return 0;
else
return LName.GetHashCode();
}
else if (LName == null)
return FName.GetHashCode();
else
return FName.GetHashCode() ^ LName.GetHashCode();
}
}
This implementation handles all the edge cases.
Read this question to know why you should also override GetHashCode().

Assuming you are using C# 3.0 or greater, try something like this:
(The following code is not tested, but should be about right)
List<client> clientList = new List<client>();
for (int i = 0; i < 5; i++)
{
client c = new client();
c.FName = "John";
c.FName = "Smith";
c.age = i;
var b = (from cl in clientList
where cl.FName = c.FName &&
cl.LName = c.LName
select cl).ToList().Count() <= 0;
if (b)
{
clientList.Add(c);
}
}

Related

Own class object attribute get overridden

I have created an object with the attributes String, and the other is a List<String>.
I have also created a static List<MyObject> where i add then all my Objects.
Now my Problem is the second attribute is getting overridden.
For example I have 3 Objects:
Object1: "Name"; List with 3 Strings
Object2: "Name2"; List with 2 Strings
Object3: "Name3"; List with 5 Strings
If i add them now to my Object List, it looks like so
Name; List with 5 Strings
Name2; List with 5 Strings
Name3; List with 5 Strings
It override the second attributes to all the other Objects in the List.
Code:
for (int i = 0; i < 100; i++)
{
if (elo.ReadObjMask(i) > 0)
{
var iRet = elo.PrepareObjectEx(0, 0, i);
maskenname = elo.ObjMName();
if (maskenname != "")
{
for (int e = 0; e < 50; e++)
{
string eigenschaft = elo.GetObjAttribName(e);
if (eigenschaft != "" && eigenschaft != "-")
{
eigenschaften.Add(eigenschaft);
}
}
allMasks.Add(maskenname);
}
else
{
// Do nothing
}
EloMask emask = new EloMask(maskenname, eigenschaften);
staticVariables.allMask.Add(emask);
eigenschaften.Clear();
}
}
Here is my object class:
public class EloMask
{
public string name;
public List<String> eigenschaften;
public EloMask(string iname, List<String> ieigenschaften)
{
name = iname;
eigenschaften = ieigenschaften;
}
}
The List<string> always points to the same instance because you are passing a reference to the list, not a copy. As a result, the list is cleared and filled again for each EloMask that you pass that list into.
To fix your issue, create a new list instead:
if (elo.ReadObjMask(i) > 0)
{
var iRet = elo.PrepareObjectEx(0, 0, i);
maskenname = elo.ObjMName();
// create a new list here!!!
var eigenschaften = new List<string>();
if (maskenname != "")
{
for (int e = 0; e < 50; e++)
{
string eigenschaft = elo.GetObjAttribName(e);
if (eigenschaft != "" && eigenschaft != "-")
{
eigenschaften.Add(eigenschaft);
}
}
allMasks.Add(maskenname);
}
EloMask emask = new EloMask(maskenname, eigenschaften);
staticVariables.allMask.Add(emask);
// clearing the list is no longer needed
}
Here is an example how you can do what you want:
public static List<Person> PersonsList = new List<Person>();
public static Random rd = new Random();
static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
{
List<string> tmpAbilities = new List<string>() {((char)rd.Next(255)).ToString(), ((char)rd.Next(255)).ToString() , ((char)rd.Next(255)).ToString() };
Person tmpPerson = new Person("TmpName_"+i,tmpAbilities);
PersonsList.Add(tmpPerson);
}
foreach (var persona in PersonsList)
{
Console.WriteLine(persona);
}
}
public class Person
{
public string Name { get; set; }
public List<string> Abilities;
public Person(string name,List<string> abilities)
{
Name = name;
Abilities = abilities;
}
public override string ToString()
{
string retVal = $"Name: {Name}\n";
foreach (var ability in Abilities)
{
retVal += $"Ability : {ability}\n";
}
return retVal;
}
}
for (int i = 0; i < 100; i++)
{
if (elo.ReadObjMask(i) > 0)
{
// Create a new listin here
eigenschaften = new List<string>();
var iRet = elo.PrepareObjectEx(0, 0, i);
maskenname = elo.ObjMName();
if (maskenname != "")
{
for (int e = 0; e < 50; e++)
{
string eigenschaft = elo.GetObjAttribName(e);
if (eigenschaft != "" && eigenschaft != "-")
{
eigenschaften.Add(eigenschaft);
}
}
allMasks.Add(maskenname);
}
else
{
// Do nothing
}
EloMask emask = new EloMask(maskenname, eigenschaften);
staticVariables.allMask.Add(emask);
}
}

Compare each class attribute value using LINQ

I have a below class. I will get two objects List<Client> data1 and List<Client> data2. I want to compare data1 and data2 with each of the attribute value.
For example, if data1 object has the LastName=a and ClientId=1,..etc and if data2 list has the same set of data i want to push that into one more list.
Any idea, how can we achieve this using LINQ/Minimal code?
public class Client
{
public int ClientId { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public string Email { get; set; }
}
using Intersect
List<Client> data1 = new List<Client>();
List<Client> data2 = new List<Client>();
List<Client> newlst = new List<Client>();
Client obj = new Client();
obj.ClientId = 1;
obj.LastName = "a";
obj.FirstName = "n";
obj.Email = "e";
data1.Add(obj);
data2.Add(obj);
obj = new Client();
obj.ClientId = 2;
obj.LastName = "a";
obj.FirstName = "f";
obj.Email = "e";
data1.Add(obj);
newlst = data1.Intersect(data2).ToList();
I have used IEqualityComparer which is used to compare both the collection and Intersect will give the common value.I have tested the code for few scenario. You can check for all the scenario.
Hope this code will be helpful.
namespace UnitTestProject
{
[TestClass]
public class CompareTwoGenericList
{
[TestMethod]
public void TestMethod1()
{
var coll = GetCollectionOne();
var col2 = GetCollectionTwo();
//Gives the equal value
var commonValue = coll.Intersect(col2, new DemoComparer()).ToList();
//Difference
var except=coll.Except(col2, new DemoComparer()).ToList();
}
public List<Demo> GetCollectionOne()
{
List<Demo> demoTest = new List<Demo>()
{
new Demo
{
id=1,
color="blue",
},
new Demo
{
id=2,
color="green",
},
new Demo
{
id=3,
color="red",
},
};
return demoTest;
}
public List<Demo> GetCollectionTwo()
{
List<Demo> demoTest = new List<Demo>()
{
new Demo
{
id=1,
color="blue",
},
new Demo
{
id=2,
color="green",
},
new Demo
{
id=4,
color="red",
},
};
return demoTest;
}
}
// Custom comparer for the Demo class
public class DemoComparer : IEqualityComparer<Demo>
{
// Products are equal if their color and id are equal.
public bool Equals(Demo x, Demo y)
{
//Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y)) return true;
//Check whether any of the compared objects is null.
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
//Check whether the demo properties are equal.
return x.color == y.color && x.id == y.id;
}
// If Equals() returns true for a pair of objects
// then GetHashCode() must return the same value for these objects.
public int GetHashCode(Demo demo)
{
//Check whether the object is null
if (Object.ReferenceEquals(demo, null)) return 0;
//Get hash code for the color field if it is not null.
int hashColor = demo.color == null ? 0 : demo.color.GetHashCode();
//Get hash code for the id field.
int hashId = demo.id.GetHashCode();
//Calculate the hash code for the product.
return hashColor ^ hashId;
}
}
}
Create Your new class ClientView
public class ClientView{
public int ClientId { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public string Email { get; set; }
}
List lst = new List();
var data = from n in db.client
select new ClientView()
{
ClientId = n.ClientId ,
LastName = n.LastName ,
FirstName = n.FirstName,
};
var data1 = from n in db.client
select new ClientView()
{
ClientId = n.ClientId ,
LastName = n.LastName ,
FirstName = n.FirstName,
};
lst.AddRange(data);
lst.AddRange(data1);
List<ClientView> lst1 = new List<ClientView>();
foreach (var singlelst in lst)
{
ClientView newClient = new ClientView ();
newClient.Id = singlelst.Id;
newClient.આપેલ = singlelst.LastName;
newClient.આપેલતારીખ = singlelst.FirstName;
lst1.Add(newClient);
}
Try this:
public IEnumerable<PropertyInfo> GetVariance(Client user)
{
foreach (PropertyInfo pi in user.GetType().GetProperties()) {
object valueUser = typeof(Client).GetProperty (pi.Name).GetValue (user);
object valueThis = typeof(Client).GetProperty (pi.Name).GetValue (this);
if (valueUser != null && !valueUser.Equals(valueThis))
yield return pi;
}
}
IEnumerable<PropertyInfo> variances = data1.GetVariance (data2);
foreach (PropertyInfo pi in variances)
Console.WriteLine (pi.Name);

add dynamic anonymous object into linq groupBy expression

I have following linq expression:
Func<Entity, object> groupQuery = item =>
new { a = item.Attributes["name"], item = item.Attributes["number"] };
var result = target.Collection.Entities.GroupBy(groupQuery).ToList();
But if i don't know, how much columns i will group (for example 3 instead of 2),and names of the Attributes stored in List Names, How should i change my groupQuery object? My first idea was to create dynamic object like this but it don't work
dynamic groupQuery= new ExpandoObject();
IDictionary<string, object> dictionary = (IDictionary<string, object>)groupQuery;
foreach (string str in Names)
{
dictionary.Add(str, str);
}
Instead of returning an object from groupQuery you can return a string. This string will be constructed from properties of objects that you want to group. Depending on the configuration it can be generated in different ways i.e. based on different properties. Here is a code that shows an idea:
public class A
{
public string Property1 { get; set; }
public string Property2 { get; set; }
public string Property3 { get; set; }
}
public enum GroupByuMode
{
GroupBy1,
GroupBy2,
GroupBy3,
}
...
var list = new List<A>();
for (int i = 0; i < 10; ++i)
for (int j = 0; j < 10; ++j)
for (int k = 0; k < 10; ++k)
list.Add(new A { Property1 = i.ToString(), Property2 = j.ToString(), Property3 = k.ToString() });
var mode = GroupByuMode.GroupBy1;
Func<A, object> func = a =>
{
if (mode == GroupByuMode.GroupBy1)
return a.Property1;
else if (mode == GroupByuMode.GroupBy2)
return String.Format("{0}_{1}", a.Property1, a.Property2);
else if (mode == GroupByuMode.GroupBy3)
return String.Format("{0}_{1}_{2}", a.Property1, a.Property2, a.Property3);
return null;
};
var res = list.GroupBy(func).ToList();
Console.WriteLine(res.Count);
mode = GroupByuMode.GroupBy2;
res = list.GroupBy(func).ToList();
Console.WriteLine(res.Count);
It works witch LINQ to Objects as shown above. You have to check if it works with LINQ to Entities or another implementation of LINQ.
answer in question
C# LINQ - How to build Group By clause dynamically
IEnumerable<string> columnsToGroupBy = new[] { Names.First()};
Names.RemoveAt(0);
Names.Aggregate(columnsToGroupBy, (current, query) => current.Concat(new[] {query}));
GroupQuery = r => new NTuple<object>(from column in columnsToGroupBy select r[column]);
///////
using System;
using System.Collections.Generic;
using System.Linq;
namespace WBTCB.AggregationService.Models.Helpers
{
public class NTuple<T> : IEquatable<NTuple<T>>
{
public NTuple(IEnumerable<T> values)
{
Values = values.ToArray();
}
public readonly T[] Values;
public override bool Equals(object obj)
{
if (ReferenceEquals(this, obj))
return true;
if (obj == null)
return false;
return Equals(obj as NTuple<T>);
}
public bool Equals(NTuple<T> other)
{
if (ReferenceEquals(this, other))
return true;
if (other == null)
return false;
var length = Values.Length;
if (length != other.Values.Length)
return false;
for (var i = 0; i < length; ++i)
if (!Equals(Values[i], other.Values[i]))
return false;
return true;
}
public override int GetHashCode()
{
return Values.Aggregate(17, (current, value) => current*37 + (!ReferenceEquals(value, null) ? value.GetHashCode() : 0));
}
}
}

Split string to list of object

I have inputs like following:
"10+18+12+13"
"10+18-12+13"
"2-5"
e.g. number followed by a "+" or "-"
I created class MathOper
public class MathOper
{
public int Num { get; set; }
public string Oper { get; set; } //this display the number will be operated.
}
I want to return list of MathOper as following
"10+18-12+13" will return
new MathOper(){Num=10,"+"}
new MathOper(){Num=18,"+"}
new MathOper(){Num=12,"-"}
new MathOper(){Num=13,"+"}
I tried to code that by this way:
public class MathOperCreator
{
private readonly string _mathString;//8+2-3
public MathOperCreator(string mathString)
{
this._mathString = mathString.Trim();
}
public List<MathOper> Create()
{
var lMo = new List<MathOper>();
int l = this._mathString.Length;//5
for (int i = 0; i < l; i = i + 2)
{
char n = _mathString[i];
int n1 = int.Parse(n.ToString(CultureInfo.InvariantCulture));
string o1 = "+";
if (i > 0)
{
o1 = _mathString[i - 1].ToString(CultureInfo.InvariantCulture);
}
var mo = new MathOper { Num = n1, Oper = o1 };
lMo.Add(mo);
}
return lMo;
}
}
I found that it is only for number with one char, if the number is two char ,such as 18 , it doesn't work.
Please advice how implement described functionality?
This is a tested Solution
//Model class
public class MathOperation
{
public Int32 Num { get; set; }
public String Operation { get; set; }
}
String testData = "10+18+12-13";
String[] GetNumbers = testData.Split(new Char[] { '+', '-' });
String[] GetOperators = Regex.Split(testData, "[0-9]+");
//remove empty entries in operator
GetOperators = GetOperators.Where(x => !string.IsNullOrEmpty(x)).ToArray();
List<MathOperation> list = new List<MathOperation>();
MathOperation mathOperation = new MathOperation();
for (int i = 0; i < GetNumbers.Count(); i++)
{
mathOperation.Num = Convert.ToInt32(GetNumbers[i]);
mathOperation.Operation = (i>GetOperators.Length)? GetOperators[i] : null;
list.Add(mathOperation);
}
This will give a list like
{Num=10,"+"}
{Num=18,"+"}
{Num=12,"-"}
{Num=13,"null"} //as in my test string there is no char after 13
if you dont want a null always a + then
mathOperation.Operation = (i>GetOperators.Length)? GetOperators[i] : "+";
then This will give a list like
{Num=10,"+"}
{Num=18,"+"}
{Num=12,"-"}
{Num=13,"+"} //as in my test string there is no char after 13
This works for me.
//you can change in to MathOper
List<Tuple<int, char>> result = new List<Tuple<int, char>>();
string _mathString = "2-2+10-13"; //Test
char sign = '-';
if (_mathString[0] != '-') //checking the first sign
{
sign = '+';
}
while (_mathString.Length > 0)
{
int nextPl = _mathString.IndexOf('+');
int nextMn = _mathString.IndexOf('-');
if (nextPl == -1 && nextMn == -1) //condition when _mathString contains only number
{
result.Add(new Tuple<int, char>(int.Parse(_mathString), sign));
break;
}
else
{
//getting the end position of first number
int end = nextPl == -1 ? nextMn : (nextMn == -1 ? nextPl : (Math.Min(nextPl, nextMn)));
//retrieving first number
result.Add(new Tuple<int, char>(int.Parse(_mathString.Substring(0, end)), sign));
_mathString = _mathString.Remove(0, end);
//retrieving next sign
sign = _mathString[0];
_mathString = _mathString.Remove(0, 1);
}
}
Try this, I think it works the way you wanted: (Easy to understand solution but not optimal)
public class MathOper
{
public int Num { get; set; }
public string Oper { get; set; } //this display the number will be operated.
}
public class MathOperCreator
{
public readonly string _mathString;//8+2-3
public MathOperCreator(string mathString)
{
this._mathString = mathString.Trim();
}
public List<MathOper> Create()
{
var lMo = new List<MathOper>();
int l = this._mathString.Length;//5
string _mathStringTemp;
char[] charArr = _mathString.ToCharArray();
if (charArr[0] != '+' || charArr[0] != '-')
{
_mathStringTemp = "+"+_mathString;
} else
{
_mathStringTemp = _mathString;
}
char[] delimitersNumb = new char[] { '+', '-' };
string[] numbers = _mathStringTemp.Split(delimitersNumb,
StringSplitOptions.RemoveEmptyEntries);
string[] operators = new string[numbers.Length];
int count = 0;
foreach (char c in _mathStringTemp)
{
if (c == '+' || c == '-')
{
operators[count] = c.ToString();
count++;
}
}
for(int i=0; i < numbers.Length; i++)
{
lMo.Add(new MathOper(){Num = int.Parse(numbers[i]), Oper = operators[i]});
Console.WriteLine(operators[i]+" "+numbers[i]);
}
return lMo;
}
}

Tarjan cycle detection help C#

Here is a working C# implementation of tarjan's cycle detection.
The algorithm is found here:
http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
public class TarjanCycleDetect
{
private static List<List<Vertex>> StronglyConnectedComponents;
private static Stack<Vertex> S;
private static int index;
private static DepGraph dg;
public static List<List<Vertex>> DetectCycle(DepGraph g)
{
StronglyConnectedComponents = new List<List<Vertex>>();
index = 0;
S = new Stack<Vertex>();
dg = g;
foreach (Vertex v in g.vertices)
{
if (v.index < 0)
{
strongconnect(v);
}
}
return StronglyConnectedComponents;
}
private static void strongconnect(Vertex v)
{
v.index = index;
v.lowlink = index;
index++;
S.Push(v);
foreach (Vertex w in v.dependencies)
{
if (w.index < 0)
{
strongconnect(w);
v.lowlink = Math.Min(v.lowlink, w.lowlink);
}
else if (S.Contains(w))
{
v.lowlink = Math.Min(v.lowlink, w.index);
}
}
if (v.lowlink == v.index)
{
List<Vertex> scc = new List<Vertex>();
Vertex w;
do
{
w = S.Pop();
scc.Add(w);
} while (v != w);
StronglyConnectedComponents.Add(scc);
}
}
Note a DepGraph is just a list of Vertex. and Vertex has a list of other Vertex which represent the edges. Also index and lowlink are initialized to -1
EDIT: This is working...I just misinterpreted the results.
The above is actually correct, I did not understand what a strongly connected component was. I was expecting the function to return an empty List of strongly connected components, yet it was returning a list of single nodes.
I believe the above is working. Feel free to use if you need it!
As of 2008 quickgraph has supported this algorithm. See the StronglyConnectedComponentsAlgorithm class for the implementation, or AlgorithmExtensions.StronglyConnectedComponents method for a usage shortcut.
Example:
// Initialize result dictionary
IDictionary<string, int> comps = new Dictionary<string, int>();
// Run the algorithm
graph.StronglyConnectedComponents(out comps);
// Group and filter the dictionary
var cycles = comps
.GroupBy(x => x.Value, x => x.Key)
.Where(x => x.Count() > 1)
.Select(x => x.ToList())
Example presented above in question isn't functional should anyone want to quickly play with it. Also note that it is stack based, which will detonate your stack if you give anything but the most trivial of graphs. Here is a working example with a unit test that models the graph presented on the Tarjan wikipedia page:
public class Vertex
{
public int Id { get;set; }
public int Index { get; set; }
public int Lowlink { get; set; }
public HashSet<Vertex> Dependencies { get; set; }
public Vertex()
{
Id = -1;
Index = -1;
Lowlink = -1;
Dependencies = new HashSet<Vertex>();
}
public override string ToString()
{
return string.Format("Vertex Id {0}", Id);
}
public override int GetHashCode()
{
return Id;
}
public override bool Equals(object obj)
{
if (obj == null)
return false;
Vertex other = obj as Vertex;
if (other == null)
return false;
return Id == other.Id;
}
}
public class TarjanCycleDetectStack
{
protected List<List<Vertex>> _StronglyConnectedComponents;
protected Stack<Vertex> _Stack;
protected int _Index;
public List<List<Vertex>> DetectCycle(List<Vertex> graph_nodes)
{
_StronglyConnectedComponents = new List<List<Vertex>>();
_Index = 0;
_Stack = new Stack<Vertex>();
foreach (Vertex v in graph_nodes)
{
if (v.Index < 0)
{
StronglyConnect(v);
}
}
return _StronglyConnectedComponents;
}
private void StronglyConnect(Vertex v)
{
v.Index = _Index;
v.Lowlink = _Index;
_Index++;
_Stack.Push(v);
foreach (Vertex w in v.Dependencies)
{
if (w.Index < 0)
{
StronglyConnect(w);
v.Lowlink = Math.Min(v.Lowlink, w.Lowlink);
}
else if (_Stack.Contains(w))
{
v.Lowlink = Math.Min(v.Lowlink, w.Index);
}
}
if (v.Lowlink == v.Index)
{
List<Vertex> cycle = new List<Vertex>();
Vertex w;
do
{
w = _Stack.Pop();
cycle.Add(w);
} while (v != w);
_StronglyConnectedComponents.Add(cycle);
}
}
}
[TestMethod()]
public void TarjanStackTest()
{
// tests simple model presented on https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
var graph_nodes = new List<Vertex>();
var v1 = new Vertex() { Id = 1 };
var v2 = new Vertex() { Id = 2 };
var v3 = new Vertex() { Id = 3 };
var v4 = new Vertex() { Id = 4 };
var v5 = new Vertex() { Id = 5 };
var v6 = new Vertex() { Id = 6 };
var v7 = new Vertex() { Id = 7 };
var v8 = new Vertex() { Id = 8 };
v1.Dependencies.Add(v2);
v2.Dependencies.Add(v3);
v3.Dependencies.Add(v1);
v4.Dependencies.Add(v3);
v4.Dependencies.Add(v5);
v5.Dependencies.Add(v4);
v5.Dependencies.Add(v6);
v6.Dependencies.Add(v3);
v6.Dependencies.Add(v7);
v7.Dependencies.Add(v6);
v8.Dependencies.Add(v7);
v8.Dependencies.Add(v5);
v8.Dependencies.Add(v8);
graph_nodes.Add(v1);
graph_nodes.Add(v2);
graph_nodes.Add(v3);
graph_nodes.Add(v4);
graph_nodes.Add(v5);
graph_nodes.Add(v6);
graph_nodes.Add(v7);
graph_nodes.Add(v8);
var tcd = new TarjanCycleDetectStack();
var cycle_list = tcd.DetectCycle(graph_nodes);
Assert.IsTrue(cycle_list.Count == 4);
}
I added a Id property to the Vertex object so it is simple to see what is being done, it isn't strictly needed. I also cleaned up some of the code a little, author was using naming from page pseudo-code, which is good for comparison, but it wasn't very informative.

Categories

Resources