bagaimana cara memeriksa apakah objek sudah ada dalam daftar


102

Saya punya daftar

  List<MyObject> myList

dan saya menambahkan item ke daftar dan saya ingin memeriksa apakah objek itu sudah ada dalam daftar.

jadi sebelum saya melakukan ini:

 myList.Add(nextObject);

Saya ingin melihat apakah nextObject sudah ada dalam daftar.

Objek "MyObject" memiliki sejumlah properti tetapi perbandingannya didasarkan pada pencocokan pada dua properti.

Apa cara terbaik untuk melakukan pemeriksaan sebelum saya menambahkan "MyObject" baru ke daftar "MyObject" ini.

Satu-satunya solusi yang saya pikirkan adalah mengubah dari daftar ke kamus dan kemudian membuat kuncinya sebagai string gabungan dari properti (ini tampaknya sedikit tidak elegan).

Adakah solusi bersih lainnya yang menggunakan list atau LINQ atau yang lainnya?

Jawaban:


153

Itu tergantung pada kebutuhan situasi spesifik. Misalnya, pendekatan kamus akan cukup bagus dengan asumsi:

  1. Daftarnya relatif stabil (tidak banyak penyisipan / penghapusan, yang kamusnya tidak dioptimalkan)
  2. Daftarnya cukup besar (jika tidak, overhead kamus tidak ada gunanya).

Jika hal di atas tidak benar untuk situasi Anda, gunakan saja metode ini Any():

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

Ini akan menghitung melalui daftar sampai menemukan kecocokan, atau sampai mencapai akhir.


Penggunaan delegasi predikat untuk list.exists adalah solusi lain lihat di bawah, tetapi jika Anda memiliki daftar yang besar dan nilai kunci dengan kamus akan jauh lebih cepat karena ini adalah tabel hash! Nikmati
Doug

1
Bagaimana cara memeriksa beberapa nilai?
Nitin Karale

80

Cukup gunakan metode Berisi . Perhatikan bahwa ini bekerja berdasarkan fungsi kesetaraanEquals

bool alreadyExist = list.Contains(item);

5
Ini tidak berhasil untuk saya, selalu dikatakan tidak ada
Si8

4
@ Si8 Jika Anda mencoba untuk membandingkan objek, Anda harus yakin bahwa implementasi IEquatable <T> .Equals diimplementasikan dengan benar untuk tipe objek Anda. Jika tidak, Anda tidak akan membandingkan konten objek. Lihat tautan Berisi yang ditunjukkan Ahmad untuk contoh bagaimana menerapkan ini.
Doug Knudsen

56

Jika tetap dapat menggunakan 2 properti tersebut, Anda dapat:

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

7

Apakah Anda yakin Anda memerlukan daftar dalam kasus ini? Jika Anda mengisi daftar dengan banyak item, kinerja akan terganggu dengan myList.Containsatau myList.Any; run-time akan menjadi kuadrat. Anda mungkin ingin mempertimbangkan untuk menggunakan struktur data yang lebih baik. Sebagai contoh,

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

Anda dapat menggunakan HashSet dengan cara berikut:

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

Tentu saja, jika definisi persamaan untuk MyClass'universal', Anda tidak perlu menulis IEqualityComparerimplementasi; Anda bisa mengganti GetHashCodedan Equalsdi kelas itu sendiri.


Ya, bool untuk V adalah favoritku. Untuk masalah ini, belum lama ini (eh, sekitar 3 minggu) HashSet tidak tersedia untuk saya karena saya sedang mengerjakan kode 2.0, dan saya berhenti dalam implementasi Mono dari HashSet karena sangat berguna :)
Jon Hanna

4

Hal lain yang perlu disebutkan adalah Anda harus memastikan bahwa fungsi kesetaraan Anda seperti yang Anda harapkan. Anda harus mengganti metode sama dengan untuk menyiapkan properti apa dari objek Anda harus cocok agar dua contoh dianggap sama.

Maka Anda bisa melakukan mylist.contains (item)


3

Berikut adalah aplikasi konsol cepat untuk menggambarkan konsep cara menyelesaikan masalah Anda.

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

Nikmati!


3

Sunting: Saya pertama kali mengatakan:


Apa yang tidak elegan tentang solusi kamus. Kelihatannya sangat elegan bagi saya, terutama karena Anda hanya perlu menyetel pembanding dalam pembuatan kamus.


Namun tentu saja, tidak anggun menggunakan sesuatu sebagai kunci jika itu juga nilainya.

Oleh karena itu saya akan menggunakan HashSet. Jika operasi nanti membutuhkan pengindeksan, saya akan membuat daftar darinya ketika Penambahan selesai, jika tidak, cukup gunakan hashset.


Saya hanya akan menggunakan ini jika daftar objek sangat besar karena tabel hash dan mereka bagus untuk pencarian cepat.
Doug

0

Sederhana tetapi berhasil

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

atau

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

-1

Jika Anda menggunakan EF core add

 .UseSerialColumn();

Contoh

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

            entity.Property(e => e.Id)
                .HasColumnName("id")
                .UseSerialColumn();
});
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.