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


102

목록이 있습니다

  List<MyObject> myList

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

그래서 이것을하기 전에 :

 myList.Add(nextObject);

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

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

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

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

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

답변:


153

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

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

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

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

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


list.exists에 대한 조건 자 델리게이트를 사용하는 것은 또 다른 해결책입니다. 아래를 참조하십시오.하지만 거대한 목록과 사전이있는 키 값이있는 경우 해시 테이블이므로 훨씬 빠릅니다! Enjoy
Doug

1
여러 값을 확인하는 방법은 무엇입니까?
니틴 Karale

80

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

bool alreadyExist = list.Contains(item);

5
이것은 나를 위해 작동하지 않았고 항상 존재하지 않는다고 말했습니다
Si8

4
@ Si8 개체를 비교하려는 경우 IEquatable <T> .Equals 구현이 개체 유형에 대해 올바르게 구현되었는지 확인해야합니다. 그렇지 않으면 개체 내용을 비교하지 않습니다. 이를 구현하는 방법에 대한 예는 Ahmad가 표시된 포함 링크를 참조하십시오.
Doug Knudsen

56

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

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

7

이 경우 목록이 필요합니까? 많은 항목으로 목록을 채우는 경우 성능이 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클래스 자체입니다.


네, V의 bool이 가장 좋았습니다. 그 문제에 대해, 내가 2.0 코드를 작업하고 있었기 때문에 HashSet을 사용할 수 없었던 것은 얼마 전 (예, 약 3 주)이 아니었고, 매우 유용하기 때문에 HashSet의 Mono 구현을 중단했습니다. :)
Jon Hanna

4

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

그런 다음 mylist.contains (item)


3

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

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]);
                }
            }
        }
    }
}

즐겨!


3

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


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


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

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


해시 테이블이기 때문에 객체 목록이 크고 빠른 조회에 좋은 경우에만 이것을 사용합니다.
Doug

0

간단하지만 작동합니다.

MyList.Remove(nextObject)
MyList.Add(nextObject)

또는

 if (!MyList.Contains(nextObject))
    MyList.Add(nextObject);

-1

EF 코어 추가를 사용하는 경우

 .UseSerialColumn();

modelBuilder.Entity<JobItem>(entity =>
        {
            entity.ToTable("jobs");

            entity.Property(e => e.Id)
                .HasColumnName("id")
                .UseSerialColumn();
});
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.