Union of two lists in LINQ not working - c#

I've a method where I'll show the books which are present in the db and the ones which are given for lent.
When the user doesn't returns the book,the book becomes inactive.So I've written a LINQ query where the new users can select a book.Then if the the user selects a lost book.He will be thrown a message that the book is not available.
Here I am using the Union to find the books which are active and the books which are lent and not return.
But the duplicate values are returning in method.
public IEnumerable<UsageType> GetUsageType(int BookID = 0)
{
_db.Configuration.ProxyCreationEnabled = false;
List<UsageType> Uresult = new List<UsageType>();
List<UsageType> result = new List<UsageType>();
try
{
if (BookID == 0)
{
result = (from Usage in _db.USAGE_TYPE
where Usage.IS_ACTIVE == true
select new
{
UsageTypeId = Usage.USAGE_TYPE_ID,
UsageTypeName = Usage.USAGE_TYPE_NAME,
IsActive = Usage.IS_ACTIVE
}).AsEnumerable()
.Select(x => new UsageType
{
UsageTypeId = x.UsageTypeId,
UsageTypeName = x.UsageTypeName,
IsActive = x.IsActive.HasValue ? x.IsActive.Value : false
}).Distinct().ToList();
}
else
{
result = (from Usage in _db.USAGE_TYPE
where Usage.IS_ACTIVE == true
select new
{
UsageTypeId = Usage.USAGE_TYPE_ID,
UsageTypeName = Usage.USAGE_TYPE_NAME,
IsActive = Usage.IS_ACTIVE
}).AsEnumerable()
.Select(x => new UsageType
{
UsageTypeId = x.UsageTypeId,
UsageTypeName = x.UsageTypeName,
IsActive = x.IsActive.HasValue ? x.IsActive.Value : false
}).ToList();
var savedUsagetype = (from Usage in _db.USAGE_TYPE
join usageCategory in _db.USAGE_CATEGORY on Usage.USAGE_TYPE_ID equals usageCategory.USAGE_TYPE_ID
join book_usage in _db.BOOK_USAGE
on usageCategory.USAGE_CATEGORY_ID equals book_usage.USAGE_CATEGORY_ID
where book_usage.Book_ID == BookID
select new
{
UsageTypeId = Usage.USAGE_TYPE_ID,
UsageTypeName = Usage.USAGE_TYPE_NAME,
IsActive = Usage.IS_ACTIVE
}).AsEnumerable()
.Select(x => new UsageType
{
UsageTypeId = x.UsageTypeId,
UsageTypeName = x.UsageTypeName,
IsActive = x.IsActive.HasValue ? x.IsActive.Value : false
}).ToList();
Uresult= result.Union(savedUsagetype).Distinct().ToList();
}
return Uresult;
}
catch (Exception ex)
{
return null;
}
}

You are comparing objects of your own class so you should implement IEquatable in your UsageType class to tell linq how to compare your objects. For example:
public class UsageType : IEquatable<UsageType>
{
public int UsageTypeId {get; set;}
...
public bool Equals(UsageType other)
{
return this.UsageTypeId == other.UsageTypeId;
}
public override bool Equals(object other)
{
return this.UsageTypeId == ((UsageType)other).UsageTypeId;
}
public override int GetHashCode()
{
return this.UsageTypeId.GetHashCode();
}
}
Now you can use UsageType to get an instance of IEqualityComparer<UsageType>:
Uresult = result.Union(savedUsageType,IEqualityComparer<UsageType>.Default).ToList();
Note: Always override object.Equals and object.GetHashcode() too. If you don't, old code which still uses the non-generic Enumerable will give unexpected results because they use other logic to compare than you'd expect.

Related

How to Join a table with a list NHibernate?

I have a list of objects like this
public class MyList
{
public int recordNo { get; set; }
public bool IsValid { get; set; }
}
var result= (from pool in context.Table.Where(prdicate)
select new ResultEntity
{
guid = pool.guid,
isValid = myList.FirstOrDefault(no => no.guid == pool.guid).IsValid //It thorws an error here
}
the error is
System.NotSupportedException:
the error caused because IsValid assign
So I want to join the list with a table, to asssign some values on it. How can I do that?
Customer customerAlias = null;
Organization organizationAlias = null;
IList<Customer> customers = session.QueryOver(() => customerAlias)
.Left.JoinAlias(x => x.Organization, () => organizationAlias)
.Where(customer => customer.Name == "Customer Name")
.And(() => customerAlias.Age > 18)
.AndNot(() => organizationAlias.Name == "Forbidden Organization")
.List();

Filter out duplicates from two lists and change object property value if duplicate

I have two lists AuthorList & AuthorList2. At the moment I am using union with simple IEqualityComparer class.
I expect to have a result list without any duplicates from AuthorList & AuthorList2 and if there are any duplicates in those lists, they need to be removed from the lists and the Author class Assigned property needs to be set true for the duplicate item.
Existing information from both AuthorLists:
ProductID & Assigned
1, false
2, false
3, false
1, false
Result list:
ProductID & Assigned
1, true
2, false
3, false
The logic needs to filter out duplicates and if both of those lists have the same element, change false -> true.
namespace HelloWorld
{
class Hello
{
static void Main()
{
List<Author> AuthorList = new List<Author>
{
new Author(1, false),
new Author(2, false),
new Author(3, false)
};
List<Author> AuthorList2 = new List<Author>
{
new Author(1, false)
};
var compareById = new AuthorComparer(false);
var result = AuthorList.Union(AuthorList2, compareById);
foreach (var item in result)
{
Console.WriteLine("Result: {0},{1}", item.ProductId, item.Assigned);
}
Console.ReadKey();
}
public class AuthorComparer : IEqualityComparer<Author>
{
private bool m_withValue;
public AuthorComparer(bool withValue)
{
m_withValue = withValue;
}
public bool Equals(Author x, Author y)
{
return (x.ProductId == y.ProductId);
}
public int GetHashCode(Author x)
{
return x.ProductId.GetHashCode();
}
}
public class Author
{
private int productId;
private bool assigned;
public Author(int productId, bool assigned)
{
this.productId = productId;
this.assigned = assigned;
}
public int ProductId
{
get { return productId; }
set { productId = value; }
}
public bool Assigned
{
get { return assigned; }
set { assigned = value; }
}
}
}
}
The code you're looking for is this:
AuthorList.ForEach(a => a.Assigned = AuthorList2.Exists(b => b.ProductId == a.ProductId));
You don't need the IEqualityComparer at all.
Full, working code:
namespace HelloWorld
{
class Hello
{
static void Main()
{
List<Author> AuthorList = new List<Author>
{
new Author(1, false),
new Author(2, false),
new Author(3, false)
};
List<Author> AuthorList2 = new List<Author>
{
new Author(1, false)
};
AuthorList.ForEach(a => a.Assigned = AuthorList2.Exists(b => b.ProductId == a.ProductId));
foreach (var item in AuthorList)
{
Console.WriteLine("Result: {0},{1}", item.ProductId, item.Assigned);
}
Console.ReadKey();
}
public class Author
{
public Author(int productId, bool assigned)
{
this.ProductId = productId;
this.Assigned = assigned;
}
public int ProductId { get; set; }
public bool Assigned { get; set; }
}
}
}
With your comparer, you can use:
foreach (var author in AuthorList.Intersect(AuthorList2, compareById))
{
author.Assigned = true;
}
You can do it without that easily enough as well if you don't need the comparer for anything else:
var author2Ids = new HashSet<int>(AuthorList2.Select(a => a.ProductId));
foreach (var author in AuthorList.Where(a => author2Ids.Contains(a.ProductId)))
{
author.Assigned = true;
}
... but if you need the comparer for anything else, or if it may get more complex, I'd stick to using that.
Try with something like this. Please look at ! carefully
//Separate out different entries from both the lists
var diffList = AuthorList.Where(x => !AuthorList2.Any(y => y.ProductId== x.ProductId && y.Assigned== x.Assigned)).ToList();
//Separate out common entries from both the list
var commonList = AuthorList.Where(x => AuthorList2.Any(y => y.ProductId== x.ProductId && y.Assigned== x.Assigned)).ToList();
//Change value of Assigned
commonList.ForEach(x => x.Assigned = !x.Assigned);
//Merge both the lists
diffList.AddRange(commonList);
POC: DotNetFiddler
This will produce a new List of elements without altering the source:
private static List<Author> FilterDuplicates(List<Author> x, List<Author> y)
{
return x.Select(author => new Author(author.ProductId, y.Exists(a => a.ProductId == author.ProductId))).ToList();
}

Linq compare two ObservableCollection<T> with Except

I have read about the IEqualityComparer interface. Here is my code (which says more then a thousand words)
static void Main(string[] args)
{
var Send = new ObservableCollection<ProdRow>() {
new ProdRow() { Code = "8718607000065", Quantity = 1 },
new ProdRow() { Code = "8718607000911", Quantity = 10 }
};
var WouldSend = new ObservableCollection<ProdRow>() {
new ProdRow() { Code = "8718607000065", Quantity = 1 },
new ProdRow() { Code = "8718607000072", Quantity = 1 },
new ProdRow() { Code = "8718607000256", Quantity = 1 },
new ProdRow() { Code = "8718607000485", Quantity = 1 },
new ProdRow() { Code = "8718607000737", Quantity = 1 },
new ProdRow() { Code = "8718607000911", Quantity = 20 }
};
//var sendToMuch = Send.Except(WouldSend).ToList();
//var sendToLittle = WouldSend.Except(Send).ToList();
//if (sendToMuch.Any() || sendToLittle.Any())
// var notGood = true;
//else
// var okay = true;
var sendToMuch = Send.ToList();
var sendToLittle = WouldSend.ToList();
foreach (var s in Send) {
var w = WouldSend.FirstOrDefault(d => d.Code.Equals(s.Code));
if (w != null) {
if (w.Quantity == s.Quantity) {
sendToMuch.Remove(s);
sendToLittle.Remove(w);
continue;
}
if (w.Quantity > s.Quantity) {
sendToLittle.Single(l => l.Code == w.Code).Quantity = (w.Quantity - s.Quantity);
sendToMuch.Remove(s);
} else {
sendToMuch.Single(l => l.Code == w.Code).Quantity = (s.Quantity - w.Quantity);
sendToLittle.Remove(s);
}
} else {
sendToMuch.Add(s);
}
}
}
The commented lines where what I would hoped that would work... the stuff below with what I ended up with.
As reference, here is my ProdRow class:
class ProdRow : INotifyPropertyChanged, IEqualityComparer<ProdRow>
{
private string _code;
private int _quantity;
public string Code {
get { return _code; }
set {
_code = value;
OnPropertyChanged("Code");
}
}
public int Quantity {
get { return _quantity; }
set {
_quantity = value;
OnPropertyChanged("Quantity");
}
}
private void OnPropertyChanged(string v) {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(v));
}
public new bool Equals(object x, object y) {
if (((ProdRow)x).Code.Equals(((ProdRow)y).Code) && ((ProdRow)x).Quantity == ((ProdRow)y).Quantity)
return true;
else
return false;
}
public int GetHashCode(object obj) {
return obj.GetHashCode();
}
public bool Equals(ProdRow x, ProdRow y) {
if (x.Code.Equals(y.Code) && x.Quantity == y.Quantity)
return true;
else
return false;
}
public int GetHashCode(ProdRow obj) {
throw new NotImplementedException();
}
public event PropertyChangedEventHandler PropertyChanged;
}
I did not expected the commented part to work, because it cannot know to decrease the int of quantity etc. but I would like to know if there is a more efficient way to do this then the solution I used (below the commented lines). Perhaps flatten the collection like a string[]?
P.S. Sorry for the "PascalCase" of Send and WouldSend
IEqualityComparer<T> is not the right interface to implement for a class whose instances you wish to compare. IEqualityComparer<T> implementations are for creating objects that do comparisons from the outside of the objects being compared, which becomes important when you need to re-define what it means for two objects to be equal without access to the code of these objects, or when you need to use different semantic for equality depending on the context.
The right interface for strongly typed equality comparison is IEquatable<T>. However, in your case all you need is overriding Object's Equals(object) and GetHashCode():
public new bool Equals(object obj) {
if (obj == this) return true;
var other = obj as ProdRow;
if (other == null) return false;
return Code.Equals(other.Code) && Quantity == other.Quantity;
}
public int GetHashCode() {
return 31*Code.GetHashCode() + Quantity;
}
As far as computing quantities goes, you can do it with negative numbers and GroupBy:
var quantityByCode = WouldSend.Select(p => new {p.Code, p.Quantity})
.Concat(Send.Select(p => new {p.Code, Quantity = -p.Quantity}))
.GroupBy(p => p.Code)
.ToDictionary(g => g.Key, g => g.Sum(p => p.Quantity));
var tooLittle = quantityByCode
.Where(p => p.Value > 0)
.Select(p => new ProdRow {Code = p.Key, Quantity = p.Value})
.ToList();
var tooMuch = quantityByCode
.Where(p => p.Value < 0)
.Select(p => new ProdRow {Code = p.Key, Quantity = -p.Value})
.ToList();

Possible to implement a conditional join clause - JOIN ON condition1 OR condition2?

Is it possible to implement a conditional join clause in Entity Framework 6? Specifically, INNER JOIN ON (boolean condition1) OR (boolean condition2).
The code below works, but calls the database twice. Is it possible to consolidate it down into one call?
There is a foreign key relationship that ties FirmFeatures.FeatureId to Nullable FirmParameters.FeatureId
var dbContext = new MyEntities();
var feature = dbContext.FirmFeatures
.Where(f => f.FeatureId == featureId)
.First();
var parameters = dbContext.FirmParameters.AsQueryable();
parameters = feature.IsDbTable
? parameters.Where(p => p.FeatureId == null)
: parameters.Where(p => p.FeatureId == featureId);
var list = parameters.ToList()
The SQL call would look something like:
SELECT feature.*, parameter.*
FROM [FirmFeature] AS feature
INNER JOIN [FirmParameter] AS parameter
ON (feature.IsDbTable = 0 AND feature.FeatureId = parameter.FeatureId) OR (feature.IsDbTable = 1 AND parameter.FeatureId IS NULL)
WHERE feature.[FeatureId] = 3
This leveraged database model first.
I'm new to the Entity Framework.
Edit2: I'm hoping to have both a features object and a parameters object loaded from the database as a result of this.
EDIT: As requested, here are the models:
{
public FirmFeature()
{ this.FirmParameters = new HashSet<FirmParameter>(); }
public byte FeatureId { get; set; }
public bool IsDbTable { get; set; }
...
public virtual ICollection<FirmParameter> FirmParameters { get; set; }
}
public partial class FirmParameter
{
public byte ParameterId { get; set; }
public Nullable<byte> FeatureId { get; set; }
...
public virtual FirmFeature FirmFeature { get; set; }
public virtual FirmParameter FirmParameter1 { get; set; }
public virtual FirmParameter FirmParameter2 { get; set; }
}
try giving this a shot:
var isDbTableQuery = dbContext.FirmFeatures.Where(f => f.FeatureId == featureId && f.IsDbTable);
var parameters = dbContext.FirmParameters.Where(p => isDbTableQuery.Any() ? p.FeatureId == null : p.FeatureId == featureId);
var list = parameters.ToList();
I cannot test it right now, but if your only problem is the two round trips you can acomplish that using two LEFT joins, and selecting the appropriate source.
Something like:
var query = from feature in dbContext.FirmFeatures
join parameter0 in dbContext.FirmParameters
on new { IsDbTable = feature.IsDbTable, FeatureId = feature.FeatureId } equals new { IsDbTable = false, FeatureId = parameter0.FeatureId ?? 0 }
into left_parameter_0
from parameter_0 in left_parameter_0.DefaultIfEmpty()
join parameter1 in dbContext.FirmParameters
on new { IsDbTable = feature.IsDbTable, FeatureId = (byte?)null } equals new { IsDbTable = true, FeatureId = parameter1.FeatureId }
into left_parameter_1
from parameter_1 in left_parameter_1.DefaultIfEmpty()
select new { Feature = feature, Parameter = parameter_0 != null ? parameter_0 : parameter_1 };
var list = query.ToList();
You can put the condition in the join statement. I'll do this in query syntax because that always reads far easier with joins:
var q = from f in dbContext.FirmFeatures
where f.FeatureId == featureId
join p in dbContext.FirmParameters on
(f.IsDbTable ? null : f.FeatureId) equals p.FeatureId
select new { p, f };
Or simply:
var q2 = from p in dbContext.FirmParameters.Include(p => p.FirmFeature)
where (p.FirmFeature.FeatureId == featureId && p.FirmFeature.IsDbTable)
|| p.Feature == null
select p;
where you use Include to get FirmParameters having their FirmFeature references loaded (if there are any).
var list = dbContext.FirmParameters
.Where(p => (p.FirmFeature.FeatureId == featureId && p.FirmFeature.IsDbTable) ?
p.FeatureId == null : p.FeatureId == featureId)
.ToList();
UPDATE
var list = dbContext.FirmParameters
.Join(dbContext.FirmFeature, p.FeatureId, f.FeatureId, (p, f) => new { Parameter = p, Feature = f})
.Where(#f => #f.Feature.FeatureId == featureId)
.Where(#p => (#p.Feature.IsDbTable ? #p.Parameter.FeatureId == null : #p.Parameter.FeatureId == featureId))
.Select(#x => new { Feature = #x.Feature, Parameter = #x.Parameter })
.DefaultIfEmpty()
.ToList();

Fastest way to check if two List<T> are equal

I have two Lists
ListA<Emp> and ListB<Emp>
both are having 1000 records.
Emp is an object of Employee Class. Below is my Employee class
public class Employee
{
int ID = 0;
string Name = String.Empty;
string Dept = String.Empty;
string Address = String.Empty;
int Age = 0;
string Email = String.Empty;
}
I want to verify if both the Lists are equal. The Emp objects may be placed in different order. Also, there might be several Emp objects which are having exactly same info in both the list. I have to verify those also.
I tried to sort the lists and compared using SequenceEqual
Enumerable.SequenceEqual(ListA.OrderBy(s => s), ListB.OrderBy(s => s)
I am getting below error
At least one object must implement IComparable.
Exception Stack trace is as below
at System.Collections.Comparer.Compare(Object a, Object b)
at System.Collections.Generic.ObjectComparer`1.Compare(T x, T y)
at System.Linq.EnumerableSorter`2.CompareKeys(Int32 index1, Int32 index2)
at System.Linq.EnumerableSorter`1.QuickSort(Int32[] map, Int32 left, Int32 right)
at System.Linq.EnumerableSorter`1.Sort(TElement[] elements, Int32 count)
at System.Linq.OrderedEnumerable`1.<GetEnumerator>d__0.MoveNext()
at System.Linq.Enumerable.SequenceEqual[TSource](IEnumerable`1 first, IEnumerable`1 second, IEqualityComparer`1 comparer)
at System.Linq.Enumerable.SequenceEqual[TSource](IEnumerable`1 first, IEnumerable`1 second)
How can I implement this ? Also it will be better if you guys can provide me the fastest way of doing this because the number of objects in List may grow to 10 million.
Thanks for your help !
EDIT: Every employee must be in both list, order does not matter. But, if ListA contains same employee object 5 times (that means some duplicate entries), and ListB contains the employee object 4 times, then ListA and ListB are not equal.
You can use SequenceEqual with a custom IEqualityComparer<Employee>:
class EmployeeComparer : IEqualityComparer<Employee>
{
public bool Equals(Employee x, Employee y)
{
if (x == null || y == null) return false;
bool equals = x.ID==y.ID && x.Name == y.Name && x.Dept == y.Dept
&& x.Address == y.Address && x.Age == y.Age && x.Email == y.Email;
return equals;
}
public int GetHashCode(Employee obj)
{
if (obj == null) return int.MinValue;
int hash = 19;
hash = hash + obj.ID.GetHashCode();
hash = hash + obj.Name.GetHashCode();
hash = hash + obj.Dept.GetHashCode();
hash = hash + obj.Address.GetHashCode();
hash = hash + obj.Age.GetHashCode();
hash = hash + obj.Email.GetHashCode();
return hash;
}
}
Now it's so simple:
listA.SequenceEqual(ListB, new EmployeeComparer());
If the order is not important and you only want to know if all employees are in both lists you can use HashSet<Employee>.SetEquals to determine if both lists contain the same people:
var empComparer = new EmployeeComparer();
bool bothEqual = new HashSet<Employee>(ListA, empComparer)
.SetEquals(new HashSet<Employee>(ListB, empComparer));
Best complexity is O(N)
Following realization with using HashSet:
Class with implementation of GetHashCode and Equals:
public class Employee
{
public int ID = 0;
public string Name = String.Empty;
public string Dept = String.Empty;
public string Address = String.Empty;
public int Age = 0;
public string Email = String.Empty;
public override int GetHashCode()
{
return
ID.GetHashCode() ^
(Name ?? String.Empty).GetHashCode() ^
(Dept ?? String.Empty).GetHashCode() ^
(Address ?? String.Empty).GetHashCode() ^
Age.GetHashCode() ^
(Email ?? String.Empty).GetHashCode()
;
}
public override bool Equals(object obj)
{
Employee other = obj as Employee;
if (obj == null)
return false;
return ID == other.ID &&
Name == other.Name &&
Dept == other.Dept &&
Address == other.Address &&
Age == other.Age &&
Email == other.Email;
}
}
Function to compare lists:
public static bool CompareLists(List<Employee> list1, List<Employee> list2)
{
if (list1 == null || list2 == null)
return list1 == list2;
if (list1.Count != list2.Count)
return false;
Dictionary<Employee, int> hash = new Dictionary<Employee, int>();
foreach (Employee employee in list1)
{
if (hash.ContainsKey(employee))
{
hash[employee]++;
}
else
{
hash.Add(employee, 1);
}
}
foreach (Employee employee in list2)
{
if (!hash.ContainsKey(employee) || hash[employee] == 0)
{
return false;
}
hash[employee]--;
}
return true;
}
If the numbers in the list are going to grow enormous (10M), you are probably going to have to consider parallelization of the look-up to get an acceptable query time.
Consider using PLINQ.
Some more clarity on what you mean by 'equal' would be good. How complex is the equivalence check? Are you checking that the objects are the same or that the objects values are the same?
Another consideration would be this; if the number of elements are going to become large, could you consider moving this check down from .NET into your database - perhaps as a stored procedure? You may find it executes more efficiently there.
reduce the list to a scalar type: int, string, ....
L1.Select(x => x.K).ToArray()
use the except method
L1.Select(x => x.K).ToArray().Except(L1.Select(x => x.K).ToArray())
If the count of the resulting set is 0 then the List are equals
L1.Select(x => x.K).ToArray().Except(L1.Select(x => x.K).ToArray()).Count()
All together
public class Program {
public static void Main(String[] args) {
List<O> L1 = new List<O>{
new O {K = 1, V = "abcd"},
new O {K = 2, V = "efgh"}
};
List<O> L2 = new List<O>{
new O {K = 1, V = "abcd"}
};
List<O> L3 = new List<O>{
new O {K = 1, V = "abcd"},
new O {K = 3, V = "ijkl"}
};
List<O> L4 = new List<O>{
new O {K = 2, V = "efgh"},
new O {K = 1, V = "abcd"}
};
Console.WriteLine(L1.Select(x => x.K).ToArray().Except(L1.Select(x => x.K).ToArray()).Count());
Console.WriteLine(L1.Select(x => x.K).ToArray().Except(L2.Select(x => x.K).ToArray()).Count());
Console.WriteLine(L1.Select(x => x.K).ToArray().Except(L3.Select(x => x.K).ToArray()).Count());
Console.WriteLine(L1.Select(x => x.K).ToArray().Except(L4.Select(x => x.K).ToArray()).Count());
}
}
public class O {
public int K { get; set; }
public String V { get; set; }
}
Exactly what it says.
Implement IComparable on the class Employee
Also need to override Equals
Due to potentially a large number of calls to GetHashCode save it and only calculate on changes.
Tested
IComparable Interface
public MainWindow()
{
InitializeComponent();
List<Person> PLa = new List<Person>();
List<Person> PLb = new List<Person>();
PLa.Add(new Person { Age = 3, Name = "Jim"});
PLa.Add(new Person { Age = 2, Name = "Jimmmy" });
PLa.Add(new Person { Age = 1, Name = "Jim" });
PLb.Add(new Person { Age = 1, Name = "Jim" });
PLb.Add(new Person { Age = 3, Name = "Jim" });
PLb.Add(new Person { Age = 2, Name = "Jimmmy" });
System.Diagnostics.Debug.WriteLine(ListSameIgnoreOrder(PLa, PLb));
}
public bool ListSameIgnoreOrder(List<Person> PLa, List<Person> PLb)
{
if (PLa.Count != PLb.Count) return false;
//PLa.Sort();
//PLb.Sort();
return Enumerable.SequenceEqual(PLa.OrderBy(s => s), PLb.OrderBy(s => s));
//for (int i = 0; i < PLa.Count; i++)
//{
// System.Diagnostics.Debug.WriteLine(
// PLa[i].Age.ToString() + " " + PLb[i].Age.ToString() + " " +
// PLa[i].Name + " " + PLb[i].Name);
// if (!PLa[i].Equals(PLb[i])) return false;
//}
//return true;
}
public class Person : object, IComparable
{
private int age = 0;
private string name = string.Empty;
private int hash;
public int Age
{
get { return age; }
set
{
if (age == value) return;
age = value;
CalcHash();
}
}
public string Name
{
get { return name; }
set
{
if (name == value) return;
name = value;
CalcHash();
}
}
public override bool Equals(Object obj)
{
//Check for null and compare run-time types.
if (obj == null || !(obj is Person)) return false;
Person f = (Person)obj;
if (f.Age != this.Age) return false;
return (string.Compare(f.name, this.name) == 0);
}
private void CalcHash()
{
hash = Age.GetHashCode() ^
(Name ?? String.Empty).GetHashCode();
}
public override int GetHashCode()
{
return hash;
//return age ^ name.GetHashCode();
}
public int CompareTo(object obj)
{
if (obj == null) return 1;
Person otherPerson = obj as Person;
if (otherPerson != null)
{
if (otherPerson.Age > this.Age) return -1;
if (otherPerson.Age < this.Age) return 1;
// compare all properties like above
return string.Compare(otherPerson.name, this.name);
}
else
throw new ArgumentException("Object is not a Person");
}
public Person() { CalcHash(); }
}
This works.
public bool EqualList(Dictionary<int, string> a, Dictionary<int, string> b)
{
if (a.Count == b.Count)
{
bool rs = false;
foreach (var i in a)
{
if (b.ContainsKey(i.Key))
{
rs = true;
}
else
{
rs = false;
break;
}
}
return rs;
}
else
{
return false;
}
Usage:
if(EqualList(List<A>.ToDictionary(k => k.Key, k => k.Value), List<B>.ToDictionary(k => k.Key, k => k.Value)){
}else{
}

Categories