Maro
Maro

Reputation: 2629

Synchronize 2 lists

What is the best fastest way to Synchronize 2 Lists?

public class UserGroup
    {
        public UserGroup(string group, string user)
        {
            this.Group = group;
            this.User = user;
        }
        public string Group { get; set; }
        public string User { get; set; }
    }


IList<UserGroup> userGroup1 = new IList<UserGroup>();
IList<UserGroup> userGroup2 = new IList<UserGroup>();

Each group has different number of members. How can i find out the different and merge both in one new list?

PS: I can change the type from IList to whatever if it would be more efficient.

Thanks

Upvotes: 2

Views: 11088

Answers (5)

babakansari
babakansari

Reputation: 89

The following could be used if the items in collections are of two different types:

 class CollectionSynchronizer<TSource, TDestination>
    {
        public Func<TSource, TDestination, bool> CompareFunc { get; set; }
        public Action<TDestination> RemoveAction { get; set; }
        public Action<TSource> AddAction { get; set; }
        public Action<TSource, TDestination> UpdateAction { get; set; }

        public void Synchronizer(ICollection<TSource> sourceItems, ICollection<TDestination> destinationItems)
        {
            // Remove items not in source from destination
            RemoveItems(sourceItems, destinationItems);

            // Add items in source to destination 
            AddOrUpdateItems(sourceItems, destinationItems);
        }

        private void RemoveItems(ICollection<TSource> sourceCollection, ICollection<TDestination> destinationCollection)
        {
            foreach (var destinationItem in destinationCollection.ToArray())
            {
                var sourceItem = sourceCollection.FirstOrDefault(item => CompareFunc(item, destinationItem));

                if (sourceItem == null)
                {
                    RemoveAction(destinationItem);
                }
            }
        }

        private void AddOrUpdateItems(ICollection<TSource> sourceCollection, ICollection<TDestination> destinationCollection)
        {
            var destinationList = destinationCollection.ToList();
            foreach (var sourceItem in sourceCollection)
            {
                var destinationItem = destinationList.FirstOrDefault(item => CompareFunc(sourceItem, item));

                if (destinationItem == null)
                {
                    AddAction(sourceItem);
                }
                else
                {
                    UpdateAction(sourceItem, destinationItem);
                }
            }
        }
    }

And the usage would be like this:

var collectionSynchronizer = new CollectionSynchronizer<string, ContentImageEntity>
            {
                CompareFunc = (communityImage, contentImage) => communityImage == contentImage.Name,
                AddAction = sourceItem =>
                {
                    var contentEntityImage = _contentImageProvider.Create(sourceItem);
                    contentEntityImages.Add(contentEntityImage);
                },
                UpdateAction = (communityImage, contentImage) =>
                {
                    _contentImageProvider.Update(contentImage);
                },
                RemoveAction = contentImage =>
                {
                    contentEntityImages.Remove(contentImage);
                }
            };

            collectionSynchronizer.Synchronizer(externalContentImages, contentEntityImages);

Upvotes: 1

Servy
Servy

Reputation: 203827

So first we need an effective way of comparing these objects. Since the default Equals and GetHashCode implementations won't be useful in your context you either need to override them, or create an IEqualityComparer. I did the latter, you can feel free to do the former if you want. Here's a simple comparer:

public class UserGroupComparer : IEqualityComparer<UserGroup>
{
    public bool Equals(UserGroup x, UserGroup y)
    {
        return x.Group == y.Group && x.User == y.User;
    }

    public int GetHashCode(UserGroup obj)
    {
        return 37 * obj.Group.GetHashCode() + 19 * obj.User.GetHashCode();
    }
}

Now that you have this comparer you can leverage LINQ to do the work for you:

var combinedList = userGroup1.Union(userGroup2, new UserGroupComparer())
    .ToList();

That will have all of the user groups that are in either list, but without any duplicates.

Upvotes: 7

Uzzy
Uzzy

Reputation: 550

You may use HashSet see following link class http://msdn.microsoft.com/en-us/library/bb383091.aspx

Upvotes: 0

greg84
greg84

Reputation: 7619

See the answer to this question: Create a list from two object lists with linq

Basically you can use this in System.Linq:

userGroup1.Union(userGroup2).ToList();

Upvotes: 0

alex
alex

Reputation: 12654

You can try:

userGroup1.Concat(userGroup2).Distinct();

And don't forget to override Equals and GetHashCode for UserGroup class.

Upvotes: 1

Related Questions