0

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 two lists:

  1. add accounts to the first list if it is available in the second (but not in the first list).
  2. 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 :\

Community
  • 1
  • 1
deostroll
  • 11,661
  • 21
  • 90
  • 161
  • Wrote code as mentioned the SO post I've mentioned. However, when I tried to execute `var lst3 = lst.Union(lst1).ToList();` I can't see any output. Not even the output of the previous console.writeline statements. – deostroll Feb 14 '11 at 03:35
  • maybe add that to your question? – John Saunders Feb 14 '11 at 04:03
  • Somehting still amiss. I've updated the post. – deostroll Feb 14 '11 at 05:01
  • To moderators: The stack overflow problem was only a bug in the code. But actual call for the post was to find a solution to merge two lists with the constraint of updating similar items from the 2nd list to the first one. So wouldn't a title pertaining to this be appropriate? – deostroll Feb 14 '11 at 05:05

2 Answers2

5

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)));
Luke Baulch
  • 3,626
  • 6
  • 36
  • 44
0

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.

Chris Hogan
  • 868
  • 6
  • 9