2

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

Maro
  • 2,579
  • 9
  • 42
  • 79
  • 3
    `new IList();` Won't compile. Even if the variable is typed as `IList` the `new` needs to use a proper `List`. – Servy Apr 30 '13 at 15:17
  • How do you want your lists merged? Should result contain all items that exists in first or second list, or only items that exists in both list? – alex Apr 30 '13 at 15:23

5 Answers5

7

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.

Servy
  • 202,030
  • 26
  • 332
  • 449
1

You can try:

userGroup1.Concat(userGroup2).Distinct();

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

alex
  • 12,464
  • 3
  • 46
  • 67
1

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);
babakansari
  • 89
  • 1
  • 4
0

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();

Community
  • 1
  • 1
greg84
  • 7,541
  • 3
  • 36
  • 45
0

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

Uzzy
  • 550
  • 3
  • 14
  • Can you please answer the question here, and provide link as supplementary information – Yahya Apr 30 '13 at 15:40
  • Different - HashSet.ExceptWith method http://msdn.microsoft.com/en-us/library/bb299875(v=vs.90).aspx Merge - HashSet.UnionWith http://msdn.microsoft.com/en-us/library/bb342097(v=vs.90).aspx – Uzzy Apr 30 '13 at 15:51
  • I meant, to post it as a comment in question itself – Yahya Apr 30 '13 at 15:55