Как сравнить два совершенно разных объекта с похожими свойствами - PullRequest
5 голосов
/ 12 ноября 2009

Это все в C # с использованием .NET 2.0.

У меня есть два списка объектов. Они не являются связанными объектами, но у них есть определенные вещи в общем, что можно сравнить, например, уникальный идентификатор на основе Guid. Эти два списка нужны быть отфильтрованы другим списком, который просто содержит Guid, которые могут совпадать или не совпадать с идентификаторы содержатся в первых двух списках.

Я думал об идее преобразования каждого списка объектов в «объект» и сортировки по что, но я не уверен, что смогу получить доступ к свойству ID, как только он будет приведен, и я думая, что метод сортировки двух списков должен быть несколько глупым, зная, что список для сортировки есть.

Что было бы лучшим способом внести в каждый список объектов, чтобы его можно было отсортировать по списку только с идентификаторами?

Ответы [ 7 ]

15 голосов
/ 13 ноября 2009

Вы должны заставить каждый из ваших различных объектов реализовывать общий интерфейс. Затем создайте IComparer для этого интерфейса и используйте его в своем роде.

2 голосов
/ 13 ноября 2009

Хорошо, если у вас есть доступ, чтобы изменить исходные классы только для того, чтобы добавить туда интерфейс, у Мэтью это было на месте. Я немного сошел с ума и определил полное решение, используя 2.0 анонимных делегатов. (Я думаю, что я сильно зависим от 3.0 Lambda; в противном случае, я бы, вероятно, написал бы это в циклах foreach, если бы я все еще использовал 2005).

По сути, создайте интерфейс с общими свойствами. Сделайте так, чтобы два класса реализовали интерфейс. Создайте общий список, приведенный в качестве интерфейса, приведите и скопируйте значения в новый список; удалите все непревзойденные элементы.

//Program Output: 
List1:
206aa77c-8259-428b-a4a0-0e005d8b016c
64f71cc9-596d-4cb8-9eb3-35da3b96f583

List2:
10382452-a7fe-4307-ae4c-41580dc69146
97f3f3f6-6e64-4109-9737-cb72280bc112
64f71cc9-596d-4cb8-9eb3-35da3b96f583

Matches:
64f71cc9-596d-4cb8-9eb3-35da3b96f583
Press any key to continue . . .


using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication8
{
    class Program
    {
        static void Main(string[] args)
        {
            //test initialization
            List<ClassTypeA> list1 = new List<ClassTypeA>();
            List<ClassTypeB> list2 = new List<ClassTypeB>();

            ClassTypeA citem = new ClassTypeA();
            ClassTypeB citem2 = new ClassTypeB();
            citem2.ID = citem.ID;

            list1.Add(new ClassTypeA());
            list1.Add(citem);
            list2.Add(new ClassTypeB());
            list2.Add(new ClassTypeB());
            list2.Add(citem2);


            //new common list. 
            List<ICommonTypeMakeUpYourOwnName> common_list = 
                        new List<ICommonTypeMakeUpYourOwnName>();

            //in english,  give me everything in list 1 
            //and cast it to the interface
            common_list.AddRange(
              list1.ConvertAll<ICommonTypeMakeUpYourOwnName>(delegate(
                  ClassTypeA x) { return (ICommonTypeMakeUpYourOwnName)x; }));

            //in english, give me all the items in the 
            //common list that don't exist in list2 and remove them. 
            common_list.RemoveAll(delegate(ICommonTypeMakeUpYourOwnName x) 
               { return list2.Find(delegate(ClassTypeB y) 
                      {return y.ID == x.ID;}) == null; });

            //show list1 
            Console.WriteLine("List1:");
            foreach (ClassTypeA item in list1)
            {
                Console.WriteLine(item.ID);
            }
            //show list2
            Console.WriteLine("\nList2:");
            foreach (ClassTypeB item in list2)
            {
                Console.WriteLine(item.ID);
            }

            //show the common items
            Console.WriteLine("\nMatches:");
            foreach (ICommonTypeMakeUpYourOwnName item in common_list)
            {
                Console.WriteLine(item.ID);
            }
        }

    }

    interface ICommonTypeMakeUpYourOwnName
    {
        Guid ID { get; set; }
    }

    class ClassTypeA : ICommonTypeMakeUpYourOwnName
    {
        Guid _ID;
        public Guid ID {get { return _ID; } set { _ID = value;}}
        int _Stuff1;
        public int Stuff1 {get { return _Stuff1; } set { _Stuff1 = value;}}
        string _Stuff2;
        public string Stuff2 {get { return _Stuff2; } set { _Stuff2 = value;}}

        public ClassTypeA()
        {
            this.ID = Guid.NewGuid();
        }
    }

    class ClassTypeB : ICommonTypeMakeUpYourOwnName
    {
        Guid _ID;
        public Guid ID {get { return _ID; } set { _ID = value;}}
        int _Stuff3;
        public int Stuff3 {get { return _Stuff3; } set { _Stuff3 = value;}}
        string _Stuff4;
        public string Stuff4 {get { return _Stuff4; } set { _Stuff4 = value;}}

        public ClassTypeB()
        {
            this.ID = Guid.NewGuid();
        }

    }
}
1 голос
/ 13 ноября 2009

Использование только методов .NET 2.0:

class Foo
{
    public Guid Guid { get; }
}

List<Foo> GetFooSubset(List<Foo> foos, List<Guid> guids)
{
    return foos.FindAll(foo => guids.Contains(foo.Guid));
}

Если ваши классы не реализуют общий интерфейс, вам придется реализовать GetFooSubset для каждого типа отдельно.

0 голосов
/ 13 ноября 2009

В сущности, Thist должен получить то, что вы хотите, но вам может быть лучше использовать linq

class T1
{
    public T1(Guid g, string n) { Guid = g; MyName = n; }
    public Guid Guid { get; set; }
    public string MyName { get; set; }
}
class T2
{
    public T2(Guid g, string n) { ID = g; Name = n; }
    public Guid ID { get; set; }
    public string Name { get; set; }
}
class Test
{
    public void Run()
    {
        Guid G1 = Guid.NewGuid();
        Guid G2 = Guid.NewGuid();
        Guid G3 = Guid.NewGuid();
        List<T1> t1s = new List<T1>() {
            new T1(G1, "one"),
            new T1(G2, "two"), 
            new T1(G3, "three") 
        };
        List<Guid> filter = new List<Guid>() { G2, G3};

        List<T1> filteredValues1 = t1s.FindAll(delegate(T1 item)
        {
            return filter.Contains(item.Guid);
        });

        List<T1> filteredValues2 = t1s.FindAll(o1 => filter.Contains(o1.Guid));
    }
}
0 голосов
/ 13 ноября 2009

Я не совсем уверен, что вы хотите в качестве конечного результата, однако ....

Если вы сравниваете свойства двух разных типов, вы можете проецировать имена свойств и соответствующие значения в два словаря. И с этой информацией сделать какую-то сортировку / разницу значений свойств.

        Guid newGuid = Guid.NewGuid();
        var classA = new ClassA{Id = newGuid};
        var classB = new ClassB{Id = newGuid};

        PropertyInfo[] classAProperties = classA.GetType().GetProperties();

        Dictionary<string, object> classAPropertyValue = classAProperties.ToDictionary(pName => pName.Name,
                                                                                pValue =>
                                                                                pValue.GetValue(classA, null));

        PropertyInfo[] classBProperties = classB.GetType().GetProperties();
        Dictionary<string, object> classBPropetyValue = classBProperties.ToDictionary(pName => pName.Name,
                                                                                pValue =>
                                                                                pValue.GetValue(classB, null));


internal class ClassB
{
    public Guid Id { get; set; }
}

internal class ClassA
{
    public Guid Id { get; set; }
}

classAPropertyValue
Count = 1
    [0]: {[Id, d0093d33-a59b-4537-bde9-67db324cf7f6]}

classBPropetyValue
Count = 1
    [0]: {[Id, d0093d33-a59b-4537-bde9-67db324cf7f6]}
0 голосов
/ 13 ноября 2009

У меня еще не было возможности использовать AutoMapper, но из того, что вы описываете, вы хотите проверить его . Из поста Джимми Богарда:

Соглашения AutoMapper

Поскольку AutoMapper выравнивается, он будет искать:

Соответствующие имена свойств

Вложенные имена свойств (Product.Name сопоставляется с ProductName, предполагая Соглашение об именах PascalCase)

Методы, начинающиеся со слова «Получить», поэтому GetTotal () отображается в Total

Любая существующая карта типов уже сконфигурировано

В основном, если вы удалили все «Точки» и «получает», AutoMapper будет сопоставлять имена свойств. Прямо сейчас, AutoMapper не дает сбоя при несовпадении типы, но по ряду других причин.

0 голосов
/ 13 ноября 2009

Я не уверен, что полностью понимаю, что вы хотите, но вы можете использовать linq, чтобы выбрать подходящие элементы из списков, а также отсортировать их. Вот простой пример, когда значения из одного списка фильтруются по другому и сортируются.

        List<int> itemList = new List<int>() { 9,6,3,4,5,2,7,8,1 };
        List<int> filterList = new List<int>() { 2, 6, 9 };

        IEnumerable<int> filtered = itemList.SelectMany(item => filterList.Where(filter => filter == item)).OrderBy(p => p);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...