PawanS
PawanS

Reputation: 7193

Compare generic Collection?

I have a

ObservableCollection<BasicClass> allCollection;
ObservableCollection<BasicClass> selectedCollection;

where

BasicClass
{
public Name {get;set;}
public Age {get;set;}
}

Now I added many BasicClass items to allCollection and only selected BasicClass to selectedCollection

SomeWhere I want to add items in selectedCollection which are not there in allCollection. I tried this

 foreach(var a in allCollection)
    {
          foreach(var s in selectedCollection)
             if(a.Name!=s.Name)
              //selectedCollection.Add(new BasicClass {Name =a.Name, Age=a.Age}); 
    }

But the problem is that this code is adding new BasicClass for each and every unmatched name, but my actuall requirement is, for each Name of allCollection compare all selectedCollection items. If it is not there then add else move for next Item.

LINQ solution could help this? Actually I achieved this by more if and flags but That looks ver hectic. My traditional solution

    foreach(var a in allCollection)
       {
           bool same = false;
           foreach(var s in selectedCollection)
             if(a.Name==s.Name)
               same=true;
        }
   if(same==false)
     selectedCollection.Add(new BasicClass {Name =a.Name, Age=a.Age}); 

And I hate this..

EDIT:

I don't want compare collection to collection. I want to compare collection1 value to collection2 all values, and if it not there then I want to add

Upvotes: 1

Views: 617

Answers (4)

Steve
Steve

Reputation: 8511

Are you sure you don't just need this?

        foreach(var a in allCollection)    
        {    
            if (!selectedCollection.Contains(a))
                selectedCollection.Add(new BasicClass {Name =a.Name, Age=a.Age});     
        }

EDIT

I've just seen your comment below about matching on name only, so the above is not really what you want:). Try this approach instead:

        foreach(var a in allCollection)
        {
            if (!selectedCollection.Any(s => a.Name == s.Name))
            {
                selectedCollection.Add(new BasicClass {Name =a.Name, Age=a.Age});     
            }
        }

EDIT

As Chris suggested you could also use "Except" to create a collection. I'm not sure this gains much, it may be quicker but it involves writing the comparer code and creates a new temporary collection. However, it is pretty succinct E.g. Once you had the comparaer written you would just need this to add your missing items to the collection:

selectedCollection.Concat(allCollection.Except(selectedCollection));

Upvotes: 1

Thomas Levesque
Thomas Levesque

Reputation: 292465

I'm not sure I understood your requirements correctly, so i may be missing the point...

Your BasicClass should implement the IEquatable<BasicClass> interface, so that two instances of BasicClass can be compared for equality:

class BasicClass : IEquatable<BasicClass>
{
    public Name {get;set;}
    public Age {get;set;}

    public bool Equals(BasicClass other)
    {
        if (other == null)
            return false;
        return string.Equals(this.Name, other.Name);
    }

    public override int GetHashCode()
    {
        return Name == null ? 0 : Name.GetHashCode();
    }
}

Now you can use the Except method to find items that are in allCollection but not in selectedCollection:

BasicClass[] notSelected = allCollection.Except(selectedCollection).ToArray();
foreach(BasicClass item in notSelected)
{
    selectedCollection.Add(item);
}

Alternatively, you can implement a IEqualityComparer<BasicClass> and pass it to Except (instead of implementing IEquatable<BasicClass> in BasicClass)

Upvotes: 1

Vman
Vman

Reputation: 3136

So basically you need a 'where-not-in'? Linq->Except is the way to go, to filter on BasicClass.name only implement the IEqualityComparer for Except.

Upvotes: 1

Chris Pitman
Chris Pitman

Reputation: 13104

You're right, this is more easily accomplished with Linq:

var itemsToAdd = allCollection.Except(selectedCollection);
foreach (var item in itemsToAdd)
    selectedCollection.Add(item);

On the other hand, this is just going to make both lists contain the exact same items. Sure this is what you want?

If BasicItem overrides 'Equals' and 'GetHashCode' based off of Name, then this is all you need. If it doesn't, then you will also need to implement an IEqualityComparer:

//Allows us to compare BasicItems as if Name is the key
class NameComparer: IEqualityComparer<BasicItem>
{
    public bool Equals(BasicItem first, BasicItem second)
    {
        return first.Name == second.Name;
    }

    public int GetHashCode(BasicItem value)
    {
        return value.Name.GetHashCode;
    }
}

You now pass an instance of this class to Except:

var itemsToAdd = allCollections.Except(selectedCollection, new NameComparer());

Upvotes: 0

Related Questions