[c#] 객체가 이미 목록에 있는지 확인하는 방법

목록이 있습니다

  List<MyObject> myList

목록에 항목을 추가하고 있으며 해당 개체가 이미 목록에 있는지 확인하고 싶습니다.

그래서 이것을하기 전에 :

 myList.Add(nextObject);

nextObject가 이미 목록에 있는지 확인하고 싶습니다.

“MyObject”개체에는 여러 속성이 있지만 비교는 두 속성의 일치를 기반으로합니다.

이 “MyObject”목록에 새 “MyObject”를 추가하기 전에 확인하는 가장 좋은 방법은 무엇입니까?

내가 생각한 유일한 해결책은 목록에서 사전으로 변경 한 다음 키를 속성의 연결된 문자열로 만드는 것입니다 (조금 불분명 해 보입니다).

목록이나 LINQ 또는 다른 것을 사용하는 다른 클리너 솔루션이 있습니까?



답변

특정 상황의 필요에 따라 다릅니다. 예를 들어, 사전 접근 방식은 다음과 같이 가정하면 매우 좋습니다.

  1. 목록이 비교적 안정적입니다 (사전이 최적화되지 않은 삽입 / 삭제가 많지 않음).
  2. 목록이 상당히 큽니다 (그렇지 않으면 사전의 오버 헤드가 무의미합니다).

위의 내용이 귀하의 상황에 맞지 않으면 다음 방법을 사용하십시오 Any().

Item wonderIfItsPresent = ...
bool containsItem = myList.Any(item => item.UniqueProperty == wonderIfItsPresent.UniqueProperty);

일치하는 항목을 찾거나 끝에 도달 할 때까지 목록을 통해 열거됩니다.


답변

Contains 메서드를 사용하기 만하면됩니다 . 등식 함수를 기반으로 작동합니다.Equals

bool alreadyExist = list.Contains(item);


답변

이 두 가지 속성을 유지 관리 할 수 ​​있다면 다음을 수행 할 수 있습니다.

bool alreadyExists = myList.Any(x=> x.Foo=="ooo" && x.Bar == "bat");


답변

이 경우 목록이 필요합니까? 많은 항목으로 목록을 채우는 경우 성능이 myList.Contains또는로 인해 저하됩니다 myList.Any. 런타임은 2 차가됩니다. 더 나은 데이터 구조 사용을 고려할 수 있습니다. 예를 들면

 public class MyClass
    {
        public string Property1 { get; set; }
        public string Property2 { get; set; }

    }

    public class MyClassComparer : EqualityComparer<MyClass>
    {
        public override bool Equals(MyClass x, MyClass y)
        {
            if(x == null || y == null)
               return x == y;

            return x.Property1 == y.Property1 && x.Property2 == y.Property2;
        }

        public override int GetHashCode(MyClass obj)
        {
            return obj == null ? 0 : (obj.Property1.GetHashCode() ^ obj.Property2.GetHashCode());
        }
    }

다음과 같은 방식으로 HashSet을 사용할 수 있습니다.

  var set = new HashSet<MyClass>(new MyClassComparer());
  foreach(var myClass in ...)
     set.Add(myClass);

물론 평등의 정의 MyClass가 ‘보편적’이라면 IEqualityComparer구현을 작성할 필요가 없습니다 . 그냥 무시할 수 GetHashCodeEquals클래스 자체입니다.


답변

언급해야 할 또 다른 요점은 평등 함수가 예상대로인지 확인해야한다는 것입니다. 두 인스턴스가 동일한 것으로 간주되기 위해 일치해야하는 개체의 속성을 설정하려면 equals 메서드를 재정의해야합니다.

그런 다음 mylist.contains (item)


답변

다음은 문제 해결 방법에 대한 개념을 설명하는 빠른 콘솔 앱입니다.

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

namespace ConsoleApplication3
{
    public class myobj
    {
        private string a = string.Empty;
        private string b = string.Empty;

        public myobj(string a, string b)
        {
            this.a = a;
            this.b = b;
        }

        public string A
        {
            get
            {
                return a;
            }
        }

        public string B
        {
            get
            {
                return b;
            }
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            List<myobj> list = new List<myobj>();
            myobj[] objects = { new myobj("a", "b"), new myobj("c", "d"), new myobj("a", "b") };


            for (int i = 0; i < objects.Length; i++)
            {
                if (!list.Exists((delegate(myobj x) { return (string.Equals(x.A, objects[i].A) && string.Equals(x.B, objects[i].B)) ? true : false; })))
                {
                    list.Add(objects[i]);
                }
            }
        }
    }
}

즐겨!


답변

편집 : 나는 처음에 말했다 :


사전 솔루션에 대해 비정상적인 점. 딕셔너리를 생성 할 때 비교기를 설정하기 만하면되기 때문에 나에게 완벽하게 우아해 보인다.


물론 가치이기도 할 때 무언가를 키로 사용하는 것은 우아하지 않습니다.

따라서 HashSet을 사용합니다. 나중에 작업에 인덱싱이 필요한 경우 추가가 완료 될 때 목록을 생성하고 그렇지 않으면 해시 셋을 사용합니다.