Как сравнить два отчетливо различных объекта с подобными свойствами

Существует 3 главных способа иметь дело с XML в целом: dom, саксофон и xpath. dom модель хороша, если можно позволить себе загрузить весь xml файл в память сразу, и Вы не возражаете иметь дело со структурами данных, и Вы смотрите на очень/больше всего модели. Модель саксофона является замечательной, если Вы только заботитесь о нескольких тегах, и/или Вы имеете дело с большими файлами и можете обработать их последовательно. xpath модель является определенным из каждого - можно привередливо выбрать пути к элементам данных, в которых Вы нуждаетесь, но она требует, чтобы больше библиотек использовало.

, Если Вы хотите простой и упакованный с Python, minidom является Вашим ответом, но это является довольно хромым, и документация, "вот документы о dom, поймите его". Это является действительно раздражающим.

Лично, мне нравится cElementTree, который является более быстрой (находящейся в c) реализацией ElementTree, который является подобной dom моделью.

я использовал системы саксофона, и во многих отношениях они - больше "pythonic" в своем чувстве, но я обычно заканчиваю тем, что создал основанные на состоянии системы для обработки их, и тот путь находится безумие (и ошибки).

я говорю, идут с minidom, если Вам нравится исследование или ElementTree, если Вы хотите хороший код, который работает хорошо.

5
задан Chris 12 November 2009 в 20:56
поделиться

7 ответов

You should make each of your different objects implement a common interface. Then create an IComparer for that interface and use it in your sort.

15
ответ дан 18 December 2019 в 09:08
поделиться

Хорошо, если у вас есть доступ для изменения ваших исходных классов только для того, чтобы добавить туда интерфейс, Мэтью сделал это правильно. Я немного сошел с ума и определил полное решение с использованием анонимных делегатов 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();
        }

    }
}
2
ответ дан 18 December 2019 в 09:08
поделиться

Using only .NET 2.0 methods:

class Foo
{
    public Guid Guid { get; }
}

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

If your classes don't implement a common interface, you'll have to implement GetFooSubset for each type individually.

1
ответ дан 18 December 2019 в 09:08
поделиться

I'm not sure that I fully understand what you want, but you can use linq to select out the matching items from the lists as well as sorting them. Here is a simple example where the values from one list are filtered on another and sorted.

        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);
0
ответ дан 18 December 2019 в 09:08
поделиться

I haven't had a chance to use AutoMapper yet, but from what you describe you wish to check it out. From Jimmy Bogard's post:

AutoMapper conventions

Since AutoMapper flattens, it will look for:

Matching property names

Nested property names (Product.Name maps to ProductName, by assuming a PascalCase naming convention)

Methods starting with the word “Get”, so GetTotal() maps to Total

Any existing type map already configured

Basically, if you removed all the “dots” and “Gets”, AutoMapper will match property names. Right now, AutoMapper does not fail on mismatched types, but for some other reasons.

0
ответ дан 18 December 2019 в 09:08
поделиться

I am not totally sure what you want as your end results, however....

If you are comparing the properties on two different types you could project the property names and corresponding values into two dictionaries. And with that information do some sort of sorting/difference of the property values.

        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
ответ дан 18 December 2019 в 09:08
поделиться

По сути, это должно дать вам то, что вы хотите, но вам может быть лучше использовать 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
ответ дан 18 December 2019 в 09:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: