Merge two lists by key of first list
My main problem description goes like this:
I have two lists of BankAccount
objects. A BankAccount
has properties such as BankCode
and AccountNumber
which uniquely identifies an account. So both the lists may contain the same bank account but they may have their Source
, Amount
, or AccountTypes
differing.
The aim here is to merge those开发者_如何学C two lists:
- add accounts to the first list if it is available in the second (but not in the first list).
- If the bank accounts are the same in both lists, update the details of the bank account in the first list with the details of the (matching) bank account in the 2nd list.
I've tried implementing the solution mentioned in one SO post. I've went and tried writing my code down at a .NET code pad site. But I am not able to get the output after trying to execute line no. 93 which I've commented.
class BankAccount
{
public string BankCode{get;set;}
public string AccountNumber{get;set;}
public string AccountType{get;set;}
public string Amount{get;set;}
public string Source{get;set;}
public override bool Equals(object obj)
{
var acc = obj as BankAccount;
return Equals(acc);
}
public override int GetHashCode()
{
return this.GetHashCode();
}
public bool Equals(BankAccount acc2)
{
if(acc2 == null) return false;
if(string.IsNullOrEmpty(acc2.BankCode)) return false;
if(string.IsNullOrEmpty(acc2.AccountNumber)) return false;
return this.BankCode.Equals(acc2.BankCode) && this.AccountNumber.Equals(acc2.AccountNumber);
}
}
//List<BankAccount> lst3 = lst.Union(lst1).ToList(); // line 93
Full code can be viewed here.
PS: I'm not sure if this could be a problem with the codepad site or not.
Update - Monday, 14 February 2011 - 4:50:24 (am) / 04:50:24 GMT
Thanx for the update. But something is still amiss. In the output, list 3's first item should have AccountType=P
and Source=lst2
. The 2nd requirement isn't met. I figure Union()
does only a part of what I need. What do I need to do satisfy the 2nd requirement.
EDIT by drachenstern: I'm not sure this title is any better, but it's definitely more informative than the previous title as to the actual question :\
Solution 1:
This solution doesn't achieve your (newly) stated 2 requirements, but aims to fix the issue in your attempt at solving the problem using a LINQ Union().
You've got a recursive call which is causing a stack overflow exception on this line (23):
public override int GetHashCode()
{
return this.GetHashCode();
}
I suggest changing it to something like this:
public override int GetHashCode()
{
return (BankCode + AccountNumber).GetHashCode();
}
EDIT:
Ensure that members BankCount and AccountNumber will never be null or an exception will be thrown. I suggest you look up standard practices for overriding the GetHashCode() method.
Resharper's autogenerated GetHashCode override: (The 397 value ensures that the numbers won't clash if the BankCode and AccountNumber are swapped. The unchecked means that there won't be overflow issues with the number *397)
public override int GetHashCode()
{
unchecked
{
return ((BankCode != null ? BankCode.GetHashCode() : 0)*397) ^ (AccountNumber != null ? AccountNumber.GetHashCode() : 0);
}
}
Solution 2:
This solution aims to achieve your 2 requirements, without using a LINQ Union().
If you are wanting to merge the lists, using the 2nd list as the preference then perhaps try this:
var mergedList = new List<BankAccount>();
// add items from lst or any duplicates from lst1
foreach (var bankAccount in lst)
{
var account = bankAccount;
var dupe = lst1.FirstOrDefault(item => item.Equals(account));
mergedList.Add(dupe ?? bankAccount);
}
// add any items in lst1 that are not duplicates
foreach (var bankAccount in lst1.Where(item=>!mergedList.Contains(item)))
{
mergedList.Add(bankAccount);
}
If you're looking for code minimization:
// add items from lst or any duplicates from lst1
var temp = lst.Select(item => lst1.FirstOrDefault(item1 => item1.Equals(item)) ?? item);
// add any items in lst1 that are not duplicates
var result = temp.Union(lst1.Where(item => !temp.Contains(item)));
The problem is this method in class BankAccount. It's causing a stack overflow because it keeps calling itself.
public override int GetHashCode()
{
return this.GetHashCode();
}
Try using this.ToString().GetHashCode() and overriding ToString with something that makes sense for the class.
精彩评论