cách kiểm tra xem đối tượng đã tồn tại trong danh sách chưa


102

Tôi có một danh sách

  List<MyObject> myList

và tôi đang thêm các mục vào danh sách và tôi muốn kiểm tra xem đối tượng đó đã có trong danh sách chưa.

vì vậy trước khi tôi làm điều này:

 myList.Add(nextObject);

Tôi muốn xem liệu nextObject đã có trong danh sách chưa.

Đối tượng "MyObject" có một số thuộc tính nhưng so sánh dựa trên sự phù hợp trên hai thuộc tính.

Cách tốt nhất để kiểm tra là gì trước khi tôi thêm "MyObject" mới vào danh sách "MyObject" này.

Giải pháp duy nhất mà tôi nghĩ ra là thay đổi từ một danh sách sang một từ điển và sau đó biến khóa thành một chuỗi các thuộc tính được nối với nhau (điều này có vẻ hơi không phù hợp).

Bất kỳ giải pháp sạch nào khác bằng cách sử dụng danh sách hoặc LINQ hoặc thứ gì khác?

Câu trả lời:


153

Nó phụ thuộc vào nhu cầu của tình hình cụ thể. Ví dụ, cách tiếp cận từ điển sẽ khá tốt nếu giả sử:

  1. Danh sách này tương đối ổn định (không có nhiều chèn / xóa, từ điển không được tối ưu hóa cho)
  2. Danh sách này khá lớn (nếu không thì chi phí của từ điển là vô nghĩa).

Nếu những điều trên không đúng với trường hợp của bạn, chỉ cần sử dụng phương pháp Any():

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

Điều này sẽ liệt kê thông qua danh sách cho đến khi tìm thấy kết quả phù hợp hoặc cho đến khi kết thúc.


Việc sử dụng đại biểu vị từ cho list.exists là một giải pháp khác, xem bên dưới, nhưng nếu bạn có danh sách lớn và giá trị khóa với từ điển sẽ nhanh hơn nhiều vì nó là một bảng băm! Thưởng thức
Doug

1
Làm thế nào để kiểm tra nhiều giá trị?
Nitin Karale

79

Đơn giản chỉ cần sử dụng phương thức Chứa . Lưu ý rằng nó hoạt động dựa trên hàm bình đẳngEquals

bool alreadyExist = list.Contains(item);

5
Điều này không hiệu quả với tôi, nó luôn nói rằng nó không tồn tại
Si8

4
@ Si8 Nếu bạn đang cố gắng so sánh các đối tượng, bạn phải chắc chắn rằng việc triển khai IEquatable <T> .Equals được thực hiện đúng cho kiểu đối tượng của bạn. Nếu không, bạn sẽ không so sánh nội dung đối tượng. Xem liên kết Chứa mà Ahmad chỉ ra để biết ví dụ về cách thực hiện điều này.
Doug Knudsen

56

Nếu có thể duy trì sử dụng 2 thuộc tính đó, bạn có thể:

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

7

Bạn có chắc bạn cần một danh sách trong trường hợp này? Nếu bạn đang điền danh sách với nhiều mục, hiệu suất sẽ bị ảnh hưởng với myList.Containshoặc myList.Any; thời gian chạy sẽ là bậc hai. Bạn có thể muốn xem xét sử dụng cấu trúc dữ liệu tốt hơn. Ví dụ,

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

Bạn có thể sử dụng HashSet theo cách sau:

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

Tất nhiên, nếu định nghĩa bình đẳng MyClassnày là 'phổ quát', bạn không cần phải viết một bản IEqualityComparertriển khai; bạn chỉ có thể ghi đè GetHashCodeEqualstrong chính lớp đó.


Vâng, bool cho V là niềm yêu thích của tôi. Đối với vấn đề đó, cách đây không lâu (khoảng 3 tuần) mà HashSet không có sẵn cho tôi vì tôi đang làm việc trên mã 2.0 và tôi đã bỏ triển khai Mono của HashSet vì nó rất hữu ích :)
Jon Hanna

4

Một điểm khác cần đề cập là bạn nên đảm bảo rằng chức năng bình đẳng của bạn là như bạn mong đợi. Bạn nên ghi đè phương thức bằng để thiết lập những thuộc tính nào của đối tượng của bạn phải khớp để hai trường hợp được coi là bằng nhau.

Sau đó, bạn chỉ có thể làm mylist.contains (item)


3

Đây là một ứng dụng bảng điều khiển nhanh để mô tả khái niệm về cách giải quyết vấn đề của bạn.

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

Thưởng thức!


3

Chỉnh sửa: Lần đầu tiên tôi nói:


Có gì không phù hợp về giải pháp từ điển. Nó có vẻ hoàn toàn thanh lịch đối với tôi, đặc biệt là vì bạn chỉ cần đặt bộ so sánh khi tạo từ điển.


Tất nhiên, sẽ không phù hợp khi sử dụng một thứ gì đó làm chìa khóa khi nó cũng có giá trị.

Vì vậy, tôi sẽ sử dụng một HashSet. Nếu các hoạt động sau này yêu cầu lập chỉ mục, tôi sẽ tạo một danh sách từ đó khi việc Thêm được hoàn tất, nếu không, chỉ cần sử dụng bộ băm.


Tôi sẽ chỉ sử dụng điều này nếu danh sách các đối tượng rất lớn vì nó là bảng băm và chúng rất tốt để tra cứu nhanh.
Doug

0

Đơn giản nhưng nó hoạt động

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

hoặc là

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

-1

Nếu bạn sử dụng thêm lõi EF

 .UseSerialColumn();

Thí dụ

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

            entity.Property(e => e.Id)
                .HasColumnName("id")
                .UseSerialColumn();
});
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.