2009-11-12 5 views
5

이것은 .NET 2.0을 사용하여 모두 C#으로 작성되었습니다.비슷한 속성을 지닌 두 개의 서로 다른 개체를 비교하는 방법

두 개의 개체 목록이 있습니다. 그것들은 관련 객체가 아니지만 GUID 기반 고유 식별자와 비교할 수있는 공통점이있는 이 있습니다. 이 두 목록에 은 처음 두 목록에있는 ID가 과 일치하거나 일치하지 않을 수있는 Guid가 포함 된 다른 목록으로 필터링해야합니다.

각 개체 목록을 '개체'로 캐스팅하고이를 으로 정렬한다는 아이디어를 생각해 보았습니다. 그러나 일단 캐스팅 된 ID 속성에 액세스 할 수 있는지 확신 할 수 없습니다. m 두 목록을 정렬하는 방법은 정렬 할 목록이 무엇인지 아는 것이 다소 바보 같아야한다고 생각합니다.

각 개체 목록을 가져 와서 ID 목록만으로 정렬 할 수있는 가장 좋은 방법은 무엇입니까?

+0

정렬 또는 필터링? 무엇을 기준으로 정렬합니까? – dtb

+0

실제로 필터링 중입니다. object.GuidId == list.GuidId는 객체를 반환합니다. – Chris

답변

15

각기 다른 객체를 공통 인터페이스로 구현해야합니다. 그런 다음 해당 인터페이스에 대한 IComparer < T>를 작성하고이를 사용자의 용도로 사용하십시오.

+3

공통 인터페이스를 구현할 수있는 경우 (하나 또는 둘 모두의 객체를 소유하지 않기 때문에) 공통 인터페이스를 구현하는 어댑터 클래스를 작성해야합니다. 그럼 당신은 황금이에요. – plinth

+0

즉, 기본적으로 각 객체를 두 객체의 공통 요소가 포함 된 클래스 (인터페이스) 유형으로 캐스팅 한 다음 결과 (동일한 유형의) 객체를 비교합니다. 인터페이스를 사용하면 명시적인 형변환 작업을 피할 수 있습니다. –

+0

Jimmy의 AutoMapper를 사용하여 관련 객체 유형에 대한 IComparer 클래스를 등록하는 것이 흥미로울 것이라고 생각합니다. 생각? –

0

나는 당신이 원하는 것을 완전히 이해하고 있는지 확신 할 수 없지만, 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); 
0

아직 AutoMapper를 사용할 수있는 기회가 없었어요,하지만 당신은 무엇을 설명에서 당신은 check it out를 바랍니다. 지미 Bogard의 게시물에서 :

AutoMapper 규칙

AutoMapper이 평평하기 때문에

, 그것은 의지에 대한 보기 : 제품 이름에

일치하는 속성 이름

중첩 된 속성 이름 (Product.Name 지도, PascalCase 명명 규칙을 가정하여)

w 단어 i 번째, 그렇게 GetTotal는()

당신은 모든 "점"과 "가져옵니다"을 제거한 경우 이미 는, 기본적으로

를 구성 기존의 형태 맵, AutoMapper 것이다 경기를 총 매핑 "가져 오기" 속성 이름. 현재 일치하지 않는 유형의 AutoMapper가 실패하지는 않지만 다른 이유로 인해

0

당신이 그러나 최종 결과로 원하는 것을 완전히 확신하지 ....

두 개의 서로 다른 유형의 속성을이 사전에 속성 이름과 해당 값을 프로젝트 수를 비교하는 경우 . 그리고 그 정보로 어떤 종류의 정렬/속성 값의 차이가 있습니다.

 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]} 
1

.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

.NET 2.0은 람다 식을 지원하지 않으며 System.Linq에 의해 추가 된 확장 메서드도 없습니다. 귀하의 예제는 적어도 .NET 3.0이 필요합니다. –

+1

@Karim : FindAll은 LINQ가 추가 한 확장 메서드가 아니라 버전 2.0 이후 .NET 프레임 워크의 일부인 List 클래스에서 제공하는 일반적인 메서드입니다. 람다 식은 C# 3.0 컴파일러를 필요로하지만 .NET 3.0은 필요하지 않습니다. – dtb

0

Thist 관련이 기본적으로 당신이 원하는 걸 얻을해야합니다 -하지만 당신은 거기에 인터페이스를 추가하는 데에만 원래의 클래스를 수정에 액세스 할 수 있으면,

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

나는 거기에 과잉 공격을 받았다. – dice

2

좋아 LINQ를 사용하여 더 나은 될 수있다, 마태는이 자리했다 에. 여기서 약간 미쳤고 2.0 익명 대리인을 사용하여 전체 솔루션을 정의했습니다. (나는 3.0 람다에 중독 된 것 같아요. 그렇지 않으면, 아마 2005를 사용하고 있다면 아마 foreach 루프에서 이것을 작성했을 것입니다).

기본적으로 공용 속성을 사용하여 인터페이스를 만듭니다. yoru가 두 클래스가 인터페이스를 구현하도록합니다. 인터페이스로 캐스팅 된 공통 목록을 작성하고 값을 새 목록으로 캐스팅 및 추출하십시오. 일치하지 않는 항목을 제거하십시오.

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

    } 
} 
+0

FYI ... OP는 2.0을 말했다; 나는 2005 VS를 가정합니다. 3.0 VS 2008 바로 가기가 없습니다. – Nathan

+0

이것은 꽤 잘 작동합니다. 너무 나쁘다 나는 받아 들여진 2 개의 대답을 줄 수 없다. – Chris

관련 문제