Bagaimana cara menggunakan LINQ Contains (string []) daripada Contains (string)


103

Saya punya satu pertanyaan besar.

Saya mendapat kueri linq untuk membuatnya terlihat seperti ini:

from xx in table
where xx.uid.ToString().Contains(string[])
select xx

Nilai dari string[]array akan menjadi angka seperti (1,45,20,10, dll ...)

Default untuk .Containsadalah .Contains(string).

Saya membutuhkannya untuk melakukan ini sebagai gantinya: .Contains(string[])...

EDIT: Satu pengguna menyarankan untuk menulis kelas ekstensi untuk string[]. Saya ingin mempelajari caranya, tetapi ada yang mau mengarahkan saya ke arah yang benar?

EDIT: UID juga akan menjadi angka. Itu sebabnya diubah menjadi string.

Membantu siapa saja?


Anda perlu mengklarifikasi seperti apakah uid itu, dan apa yang dianggap cocok.
James Curran

3
Sebuah contoh akan menyenangkan. Bagi saya sepertinya pertanyaannya meminta UID seperti: CA1FAB689C33 dan array seperti: {"42", "2259", "CA"}
Thomas Bratt

3
Berlawanan lebih masuk akal: string []. Berisi (xx.uid)
majkinetor

Jawaban:


87

spoulson hampir benar, tetapi Anda harus membuat List<string>dari string[]pertama. Sebenarnya List<int>akan lebih baik jika uid juga int. List<T>mendukung Contains(). Melakukan uid.ToString().Contains(string[])akan menyiratkan bahwa uid sebagai string berisi semua nilai dari array sebagai substring ??? Bahkan jika Anda benar-benar menulis metode ekstensi, pengertiannya akan salah.

[EDIT]

Kecuali jika Anda mengubahnya dan menulisnya string[]seperti yang diperlihatkan Mitch Wheat, Anda hanya dapat melewati langkah konversi.

[ENDEDIT]

Inilah yang Anda inginkan, jika Anda tidak melakukan metode ekstensi (kecuali Anda sudah memiliki kumpulan uids potensial sebagai int - maka gunakan List<int>()saja). Ini menggunakan sintaks metode berantai, yang menurut saya lebih bersih, dan melakukan konversi ke int untuk memastikan bahwa kueri dapat digunakan dengan lebih banyak penyedia.

var uids = arrayofuids.Select(id => int.Parse(id)).ToList();

var selected = table.Where(t => uids.Contains(t.uid));

Terima kasih. Itu jawaban yang benar ... Satu pemikiran lagi? Katakanlah arrayuids juga merupakan query LINQ. Dengan cara apa pun Anda bisa menurunkan kedua pernyataan menjadi hanya satu kueri dari database?
SpoiledTechie.com

4
Menurut MSDN, string [] mengimplementasikan IEnumerable <T>, yang memiliki metode Contains. Oleh karena itu, tidak perlu mengonversi larik menjadi IList <T>. msdn.microsoft.com/en-us/library/19e6zeyy.aspx
spoulson

.ToString () terakhir melempar kesalahan untuk saya. Secara khusus, LINQ ke Entitas tidak mengenali metode metode 'System.String ToString ()', dan metode ini tidak dapat diterjemahkan ke dalam ekspresi penyimpanan .... Setelah menghapusnya, lambda berfungsi untuk saya.
Sam Stange

Saya suka ini, sangat mudah sehingga saya tidak pernah mengingatnya.
Olaj

@SamStange - satu masalah dengan LINQ adalah ada begitu banyak varian dan abstraksinya "bocor", terkadang Anda perlu mengetahui varian mana yang Anda gunakan untuk membuat kueri dengan benar. Seperti yang tertulis, ini akan berfungsi untuk LINQ ke objek (dan mungkin LINQ ke SQL). Untuk EF, Anda akan melakukannya sebaliknya dan membangun koleksi di memori sebagai List<int>gantinya dan melewatkan ToStringpanggilan.
tvanfosson

36

Jika Anda benar-benar ingin mereplikasi Contains , tetapi untuk sebuah array, berikut adalah metode ekstensi dan kode contoh untuk penggunaan:

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

namespace ContainsAnyThingy
{
    class Program
    {
        static void Main(string[] args)
        {
            string testValue = "123345789";

            //will print true
            Console.WriteLine(testValue.ContainsAny("123", "987", "554")); 

            //but so will this also print true
            Console.WriteLine(testValue.ContainsAny("1", "987", "554"));
            Console.ReadKey();

        }
    }

    public static class StringExtensions
    {
        public static bool ContainsAny(this string str, params string[] values)
        {
            if (!string.IsNullOrEmpty(str) || values.Length > 0)
            {
                foreach (string value in values)
                {
                    if(str.Contains(value))
                        return true;
                }
            }

            return false;
        }
    }
}

2
+1 @Jason, Anda harus mengirimkan ini sepenuhnya ke ExtensionMethod.net. Terima kasih untuk kode yang hebat, ini memecahkan masalah saya hari ini!
p. Campbell

4
Saya pikir maksud Anda! String.IsNullOrEmpty (str) && values.Length> 0
Greg Bogumil

Kamu benar. Saya mengubahnya, meski tidak berdampak fungsional. Saya menggunakan fungsi seperti ini di tempat kerja. Saya harus memeriksanya!
Jason Jackson

@JasonJackson Saya menyadari ini sudah tua (ish), tetapi (seperti yang disebutkan Greg) tidakkah Anda menginginkan "dan juga" daripada "atau yang lain" dalam persyaratan itu?
Tieson T.

@TiesonT. Baik kondisional "or else" dan "dan juga" akan berakhir dengan hasil yang sama yang dikembalikan oleh fungsi; jika !string.IsNullOrEmpty(str)pemeriksaan berhasil, menyebabkan values.Length > 0kondisi diabaikan, tetapi panjang Nilai adalah 0 , maka ia akan pergi ke foreachdan kemudian segera putus karena tidak ada entri dalam larik, langsung menuju ke return false.
Meowmaritus

20

Coba berikut ini.

string input = "someString";
string[] toSearchFor = GetSearchStrings();
var containsAll = toSearchFor.All(x => input.Contains(x));

2
Saya sangat berharap orang-orang akan meninggalkan komentar ketika mereka menilai Anda. Apalagi jawaban yang saya berikan 100% benar.
JaredPar

Bukan saya, tetapi bukankah Semua () mengembalikan hanya bool yang menunjukkan di mana semua item cocok dengan kondisi? Dan menginisialisasi toSearchFor ke null menjamin NullReferenceException.
Lucas

Saya mengedit masalah nol menjadi apa yang ingin saya ketik. Ya di Semua. Ini secara efektif memastikan bahwa semua string di toSearchFor dimuat dalam string input.
JaredPar

6
Saya tidak melihat bagaimana ini menjawab pertanyaan sama sekali. Apakah pertanyaan itu berubah pada Anda?
tvanfosson

15

LINQ di .NET 4.0 memiliki opsi lain untuk Anda; metode .Any ();

string[] values = new[] { "1", "2", "3" };
string data = "some string 1";
bool containsAny = values.Any(data.Contains);

1
Jawaban yang bagus, ekspresi dengan Any()dan All()metode sangat sederhana :) Saya bisa menggunakan t => words.All(w => t.Title.Contains(w)).
alkohol itu jahat

7

Atau jika Anda sudah memiliki datanya dalam daftar dan lebih memilih format Linq yang lain :)

List<string> uids = new List<string>(){"1", "45", "20", "10"};
List<user> table = GetDataFromSomewhere();

List<user> newTable = table.Where(xx => uids.Contains(xx.uid)).ToList();

3

Bagaimana tentang:

from xx in table
where stringarray.Contains(xx.uid.ToString())
select xx

NotSupportedException: Operator perbandingan tidak didukung untuk jenis 'System.String []' Terima kasih, tapi coba lagi?
SpoiledTechie.com

+1, jika ini yang mereka inginkan. Tidak terlalu jelas dari pertanyaannya.
Lucas

2

Ini adalah contoh salah satu cara menulis metode ekstensi (catatan: Saya tidak akan menggunakan ini untuk array yang sangat besar; struktur data lain akan lebih sesuai ...):

namespace StringExtensionMethods
{
    public static class StringExtension
    {
        public static bool Contains(this string[] stringarray, string pat)
        {
            bool result = false;

            foreach (string s in stringarray)
            {
                if (s == pat)
                {
                    result = true;
                    break;
                }
            }

            return result;
        }
    }
}

1
yang akan identik dengan public static bool Contains (string ini [] stringarray, string pat) {return Array.IndexOf (stringarray, pat)! = -1; }
James Curran

5
string [] mengimplementasikan IEnumerable <string>, sehingga ia sudah memiliki metode ekstensi Contains (string). Mengapa kami menerapkan ulang ini?
Lucas

2

Ini adalah jawaban yang terlambat, tapi saya yakin masih berguna .
Saya telah membuat paket nuget NinjaNye.SearchExtension yang dapat membantu memecahkan masalah ini .:

string[] terms = new[]{"search", "term", "collection"};
var result = context.Table.Search(terms, x => x.Name);

Anda juga dapat mencari beberapa properti string

var result = context.Table.Search(terms, x => x.Name, p.Description);

Atau lakukan RankedSearchpengembalian IQueryable<IRanked<T>>mana yang hanya menyertakan properti yang menunjukkan berapa kali istilah pencarian muncul:

//Perform search and rank results by the most hits
var result = context.Table.RankedSearch(terms, x => x.Name, x.Description)
                     .OrderByDescending(r = r.Hits);

Ada panduan yang lebih luas di halaman GitHub proyek: https://github.com/ninjanye/SearchExtensions

Semoga ini bisa membantu pengunjung di masa depan


1
Ya, ini dibuat secara khusus untuk menargetkan Entity Framework
NinjaNye

1
Bisakah saya menggunakan ini dengan metode .Where () juga?
Hamza Khanzada

Ya, itu berfungsi IQueryabledan IEnumerable- jauhkan saja jika Anda merantai itu dari IEnumerable, itu akan berjalan dalam memeory daripada membuat kueri dan mengirimkannya ke sumber
NinjaNye

2

Metode ekstensi Linq. Akan bekerja dengan objek IEnumerable:

    public static bool ContainsAny<T>(this IEnumerable<T> Collection, IEnumerable<T> Values)
    {
        return Collection.Any(x=> Values.Contains(x));
    }

Pemakaian:

string[] Array1 = {"1", "2"};
string[] Array2 = {"2", "4"};

bool Array2ItemsInArray1 = List1.ContainsAny(List2);

1

Saya yakin Anda juga bisa melakukan hal seperti ini.

from xx in table
where (from yy in string[] 
       select yy).Contains(xx.uid.ToString())
select xx

Sama seperti "where stringArray.Contains (xx.uid.ToString ())", tidak perlu membungkusnya dalam kueri
Lucas

0

Jadi, apakah saya berasumsi dengan benar bahwa uid adalah Unique Identifier (Guid)? Apakah ini hanya contoh skenario yang mungkin atau apakah Anda benar-benar mencoba menemukan panduan yang cocok dengan array string?

Jika ini benar, Anda mungkin ingin benar-benar memikirkan kembali seluruh pendekatan ini, ini sepertinya ide yang sangat buruk. Anda mungkin harus mencoba untuk mencocokkan Panduan ke Panduan

Guid id = new Guid(uid);
var query = from xx in table
            where xx.uid == id
            select xx;

Sejujurnya saya tidak bisa membayangkan skenario di mana mencocokkan array string menggunakan "berisi" ke konten Panduan akan menjadi ide yang bagus. Untuk satu hal, Contains () tidak akan menjamin urutan angka dalam Panduan sehingga Anda berpotensi mencocokkan beberapa item. Belum lagi membandingkan panduan dengan cara ini akan jauh lebih lambat daripada hanya melakukannya secara langsung.


0

Anda harus menuliskannya sebaliknya, memeriksa daftar id pengguna Anda yang memiliki hak istimewa berisi id pada baris tabel itu:

string[] search = new string[] { "2", "3" };
var result = from x in xx where search.Contains(x.uid.ToString()) select x;

LINQ berperilaku cukup cerah di sini dan mengubahnya menjadi pernyataan SQL yang baik:

sp_executesql N'SELECT [t0].[uid]
FROM [dbo].[xx] AS [t0]
WHERE (CONVERT(NVarChar,[t0].[uid]))
IN (@p0, @p1)',N'@p0 nvarchar(1),
@p1 nvarchar(1)',@p0=N'2',@p1=N'3'

yang pada dasarnya menyematkan konten larik 'pencarian' ke dalam kueri sql, dan melakukan pemfilteran dengan kata kunci 'IN' dalam SQL.


Ini berfungsi dengan baik selama Anda tidak memiliki lebih dari 2100 parameter.
jpierson

0

Saya berhasil menemukan solusi, tetapi tidak bagus karena memerlukan penggunaan AsEnumerable () yang akan mengembalikan semua hasil dari DB, untungnya saya hanya memiliki 1k catatan di tabel sehingga tidak terlalu terlihat, tapi begini .

var users = from u in (from u in ctx.Users
                       where u.Mod_Status != "D"
                       select u).AsEnumerable()
            where ar.All(n => u.FullName.IndexOf(n,
                        StringComparison.InvariantCultureIgnoreCase) >= 0)
            select u;

Berikut postingan asli saya:

Bagaimana Anda melakukan yang sebaliknya? Saya ingin melakukan sesuatu seperti berikut dalam kerangka entitas.

string[] search = new string[] { "John", "Doe" };
var users = from u in ctx.Users
            from s in search
           where u.FullName.Contains(s)
          select u;

Yang saya inginkan adalah menemukan semua pengguna di mana Nama Lengkap mereka berisi semua elemen dalam `pencarian '. Saya telah mencoba sejumlah cara berbeda, yang semuanya belum berhasil untuk saya.

Saya juga sudah mencoba

var users = from u in ctx.Users select u;
foreach (string s in search) {
    users = users.Where(u => u.FullName.Contains(s));
}

Versi ini hanya menemukan yang berisi elemen terakhir dalam larik pencarian.


0

Solusi terbaik yang saya temukan adalah melanjutkan dan membuat Fungsi Table-Valued dalam SQL yang menghasilkan hasil, seperti ::

CREATE function [dbo].[getMatches](@textStr nvarchar(50)) returns @MatchTbl table(
Fullname nvarchar(50) null,
ID nvarchar(50) null
)
as begin
declare @SearchStr nvarchar(50);
set @SearchStr = '%' + @textStr + '%';
insert into @MatchTbl 
select (LName + ', ' + FName + ' ' + MName) AS FullName, ID = ID from employees where LName like @SearchStr;
return;
end

GO

select * from dbo.getMatches('j')

Kemudian, Anda cukup menyeret fungsi ke desainer LINQ.dbml Anda dan memanggilnya seperti Anda melakukan objek lain. LINQ bahkan mengetahui kolom dari fungsi yang Anda simpan. Saya menyebutnya seperti ini ::

Dim db As New NobleLINQ
Dim LNameSearch As String = txt_searchLName.Text
Dim hlink As HyperLink

For Each ee In db.getMatches(LNameSearch)
   hlink = New HyperLink With {.Text = ee.Fullname & "<br />", .NavigateUrl = "?ID=" & ee.ID}
   pnl_results.Controls.Add(hlink)
Next

Sangat sederhana dan benar-benar memanfaatkan kekuatan SQL dan LINQ dalam aplikasi ... dan Anda tentu saja dapat membuat tabel apa pun yang dinilai fungsi yang Anda inginkan untuk efek yang sama!


0

Saya percaya bahwa apa yang benar-benar ingin Anda lakukan adalah: bayangkan skenario Anda memiliki dua database dan mereka memiliki tabel produk yang sama Dan Anda ingin memilih produk dari tabel "A" yang memiliki kesamaan id dengan "B"

menggunakan metode berisi akan terlalu rumit untuk melakukan ini yang kami lakukan adalah persimpangan, dan ada metode yang disebut persimpangan untuk itu

contoh dari msdn: http://msdn.microsoft.com/en-us/vcsharp/aa336761.aspx#intersect1

int [] angka = (0, 2, 4, 5, 6, 8, 9); int [] bilanganB = (1, 3, 5, 7, 8); var = commonNumbers numbersA.Intersect (numbersB);

Saya pikir apa yang Anda butuhkan mudah diselesaikan dengan persimpangan


0

Periksa metode ekstensi ini:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace ContainsAnyProgram
{
    class Program
    {
        static void Main(string[] args)
        {
            const string iphoneAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 5_0 like...";

            var majorAgents = new[] { "iPhone", "Android", "iPad" };
            var minorAgents = new[] { "Blackberry", "Windows Phone" };

            // true
            Console.WriteLine(iphoneAgent.ContainsAny(majorAgents));

            // false
            Console.WriteLine(iphoneAgent.ContainsAny(minorAgents));
            Console.ReadKey();
        }
    }

    public static class StringExtensions
    {
        /// <summary>
        /// Replicates Contains but for an array
        /// </summary>
        /// <param name="str">The string.</param>
        /// <param name="values">The values.</param>
        /// <returns></returns>
        public static bool ContainsAny(this string str, params string[] values)
        {
            if (!string.IsNullOrEmpty(str) && values.Length > 0)
                return values.Any(str.Contains);

            return false;
        }
    }
}


0

Mencoba:

var stringInput = "test";
var listOfNames = GetNames();
var result = from names in listOfNames where names.firstName.Trim().ToLower().Contains(stringInput.Trim().ToLower());
select names;

Meskipun kode ini dapat menjawab pertanyaan, memberikan konteks tambahan tentang bagaimana dan / atau mengapa kode ini memecahkan masalah akan meningkatkan nilai jangka panjang jawaban.
Francesco Menzani

0
var SelecetdSteps = Context.FFTrakingSubCriticalSteps
             .Where(x => x.MeetingId == meetid)
             .Select(x =>    
         x.StepID  
             );

        var crtiticalsteps = Context.MT_CriticalSteps.Where(x =>x.cropid==FFT.Cropid).Select(x=>new
        {
            StepID= x.crsid,
            x.Name,
            Checked=false

        });


        var quer = from ax in crtiticalsteps
                   where (!SelecetdSteps.Contains(ax.StepID))
                   select ax;

0
        string texto = "CALCA 40";
        string[] descpart = texto.Split(' ');

        var lst = (from item in db.InvItemsMaster
                   where descpart.All(val => item.itm_desc.Contains(val))
                   select item
                    ).ToList();
        Console.WriteLine("ITM".PadRight(10) + "DESC".PadRight(50)+"EAN".PadRight(14));
        foreach(var i in lst)
        {
           

            Console.Write(i.itm_id.ToString().PadRight(10));
            Console.Write(i.itm_desc.ToString().PadRight(50));
            Console.WriteLine(i.itm_ean.ToString().PadRight(14));


        }

        Console.ReadKey();

Kami, datanglah ke SO. Harap jangan memberikan jawaban "hanya kode". Bisakah Anda menambahkan beberapa penjelasan bagaimana ini menyelesaikan masalah dan belum tercakup oleh 21 jawaban lainnya?
marsh-wiggle

-1
string[] stringArray = {1,45,20,10};
from xx in table 
where stringArray.Contains(xx.uid.ToString()) 
select xx

-2
Dim stringArray() = {"Pink Floyd", "AC/DC"}
Dim inSQL = From alb In albums Where stringArray.Contains(alb.Field(Of String)("Artiste").ToString())
Select New With
  {
     .Album = alb.Field(Of String)("Album"),
     .Annee = StrReverse(alb.Field(Of Integer)("Annee").ToString()) 
  }
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.