LINQ Contains (string []) 'i Contains (string) yerine nasıl kullanabilirim?


102

Büyük bir sorum var.

Basitçe şöyle görünmesini istediğim bir linq sorgum var:

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

Dizinin değerleri string[](1,45,20,10, vb.) Gibi sayılar olacaktır.

Varsayılan değer .Containsşudur .Contains(string).

Bunun yerine bunu yapmam gerekiyor: .Contains(string[])...

DÜZENLEME: Bir kullanıcı için bir uzantı sınıfı yazmayı önerdi string[]. Nasıl olduğunu öğrenmek isterim ama beni doğru yöne yönlendirmeye istekli olan var mı?

DÜZENLEME: uid ayrıca bir sayı olacaktır. Bu yüzden bir dizgeye dönüştürülür.

Kimseye yardım et?


Bir kullanıcı kimliğinin neye benzeyeceğini ve neyin eşleşme olarak kabul edileceğini netleştirmeniz gerekir.
James Curran

3
Bir örnek güzel olurdu. Bana sanki soru şu gibi bir UID istiyormuş gibi geliyor: CA1FAB689C33 ve şöyle bir dizi: {"42", "2259", "CA"}
Thomas Bratt

3
Tersi daha mantıklı: string []. İçerir (xx.uid)
majkinetor

Yanıtlar:


86

spoulson neredeyse doğru vardır, ancak bir oluşturmanız gerekir List<string>dan string[]ilk. Aslında List<int>, uid de olursa a daha iyi olur int. List<T>destekler Contains(). Bunu yapmak uid.ToString().Contains(string[]), bir dizge olarak uid'in alt dizge olarak dizinin tüm değerlerini içerdiğini ima eder ??? Uzatma yöntemini yazmış olsanız bile anlamı yanlış olacaktır.

[DÜZENLE]

Onu değiştirip string[]Mitch Wheat'ın gösterdiği gibi yazmadıkça, dönüşüm adımını atlayabilirsiniz.

[ENDEDIT]

Uzantı yöntemini yapmazsanız istediğiniz şey şudur (potansiyel uidlerin ints olarak koleksiyonuna sahip değilseniz - o zaman List<int>()bunun yerine kullanın). Bu, daha temiz olduğunu düşündüğüm zincirleme yöntem sözdizimini kullanır ve sorgunun daha fazla sağlayıcıyla kullanılabilmesini sağlamak için int'e dönüştürür.

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

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

Teşekkür ederim. Doğru cevaptı ... Bir düşünce daha? Diyelim ki arrayuids aynı zamanda bir linq sorgusu. Her iki ifadeyi de veritabanından tek bir sorguya indirmenin bir yolu var mı?
SpoiledTechie.com

4
MSDN'ye göre, string [], Contains yöntemine sahip IEnumerable <T> 'yi uygular. Bu nedenle, diziyi IList <T> 'ye dönüştürmek gerekli değildir. msdn.microsoft.com/en-us/library/19e6zeyy.aspx
spoulson

Son .ToString () benim için hatalar atıyor. Özellikle, LINQ to Entities, 'System.String ToString ()' yöntemini tanımıyor ve bu yöntem bir mağaza ifadesine çevrilemez .... Kaldırıldıktan sonra lambda benim için çalıştı.
Sam Stange

Bunu seviyorum, o kadar kolay ki hiç hatırlamıyorum.
Olaj

@SamStange - LINQ ile ilgili bir sorun, çok fazla değişken olması ve soyutlamanın "sızıntılı" olmasıdır, bazen sorguyu doğru bir şekilde oluşturmak için hangi varyantı kullandığınızı bilmeniz gerekir. Yazıldığı gibi bu, nesnelere LINQ için işe yarar (ve LINQ to SQL olabilir). EF için, bunu tam tersi şekilde yaparsınız ve List<int>bunun yerine koleksiyonu bellekte inşa eder ve ToStringaramayı atlarsınız.
tvanfosson

37

Eğer gerçekten kopyalamazlar arıyorsanız içerir , ancak bir dizi için, burada bir olan uzatma yöntemi kullanımı için ve örnek kod:

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, bunu tamamen ExtensionMethod.net'e göndermelisin Harika kod için teşekkürler, bugün sorunumu çözdü!
p.campbell

4
Sanırım! String.IsNullOrEmpty (str) && values.Length> 0
Greg Bogumil

Haklısın. İşlevsel bir etkisi olmasa da değiştirdim. İşte böyle bir işlevi kullanıyorum. Kontrol etmem gerekecek!
Jason Jackson

@JasonJackson Bunun eski (ish) olduğunun farkındayım, ancak (Greg'in bahsettiği gibi) bu koşulda bir "veya başka" yerine "ve ayrıca" istemiyor musunuz?
Tieson T.

@TiesonT. Hem "ya da başka" hem de "ve ayrıca" koşul ifadeleri, işlev tarafından döndürülen aynı sonucu verir; eğer !string.IsNullOrEmpty(str)kontrol başarılı olursa, values.Length > 0koşulun yok sayılmasına neden olur , ancak Değerlerin uzunluğu 0 ise , o zaman foreachdiziye gider ve sonra hemen kesilir, çünkü dizide hiçbir girdi yoktur, doğrudan return false.
Meowmaritus

20

Takip etmeyi dene.

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

2
İnsanların sizi not aldıklarında bir yorum bırakmalarını gerçekten isterim. Özellikle verdiğim cevap% 100 doğru olduğu için.
JaredPar

Ben değildim, ancak All (), tüm öğelerin koşulla eşleştiği yeri belirten bir bool döndürmez mi? Ve null için toSearchFor başlatıldığında bir NullReferenceException garanti edilir.
Lucas

Boş konuyu yazmak istediğim şey olacak şekilde düzenledim. Tümünde Evet. Bu, toSearchFor'daki tüm dizelerin girdi dizesi içinde yer almasını etkili bir şekilde sağlar.
JaredPar

6
Bunun soruyu nasıl yanıtladığını hiç anlamıyorum. Soru size mi dönüştü?
tvanfosson

15

.NET 4.0'da LINQ sizin için başka bir seçeneğe sahiptir; .Any () yöntemi;

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

1
Harika cevap, ifadeler Any()ve All()yöntemler çok basit :) Kullanabilirim t => words.All(w => t.Title.Contains(w)).
alkol kötüdür

7

Veya zaten bir listede veri varsa ve diğer Linq formatını tercih ediyorsanız :)

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

Peki ya:

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

NotSupportedException: Karşılaştırma işleçleri 'System.String []' türü için desteklenmiyor Teşekkürler ama tekrar deneyin mi?
SpoiledTechie.com

+1, eğer gerçekten istedikleri buysa. Sorudan çok net değil.
Lucas

2

Bu, bir uzantı yöntemi yazmanın bir yolunun bir örneğidir (not: Bunu çok büyük diziler için kullanmazdım; başka bir veri yapısı daha uygun olurdu ...):

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
bu public static bool ile aynı olacaktır (bu string [] stringarray, string pat) {return Array.IndexOf (stringarray, pat)! = -1; }
James Curran

5
string [], IEnumerable <string> 'i uygular, bu nedenle zaten bir Contains (string) uzantı yöntemine sahiptir. Bunu neden yeniden uyguluyoruz?
Lucas

2

Bu geç bir cevap, ancak yine de faydalı olduğuna inanıyorum . Bu sorunu çözmeye yardımcı olabilecek NinjaNye.SearchExtension nuget paketini
yarattım . :

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

Birden çok dize özelliğini de arayabilirsiniz

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

Veya arama terimlerinin kaç kez göründüğünü gösteren bir özelliği içeren bir RankedSearchhangi döndürür gerçekleştirin IQueryable<IRanked<T>>:

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

GitHub projeleri sayfasında daha kapsamlı bir rehber var: https://github.com/ninjanye/SearchExtensions

Umarım bu gelecekteki ziyaretçilere yardımcı olur


1
Evet, Entity Framework'ü hedeflemek için özel olarak oluşturuldu
NinjaNye

1
Bunu .Where () yöntemiyle de kullanabilir miyim?
Hamza Khanzada

Evet, işe yarıyor IQueryableve IEnumerable- sadece uzak durun, eğer onu bir IEnumerable'dan zincirlerseniz, bir sorgu oluşturup kaynağa göndermek yerine
hatıra olarak çalışacaktır

2

Linq uzatma yöntemi. Herhangi bir IEnumerable nesnesiyle çalışacak:

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

Kullanım:

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

bool Array2ItemsInArray1 = List1.ContainsAny(List2);

1

Bunun gibi bir şey de yapabileceğine inanıyorum.

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

"StringArray.Contains (xx.uid.ToString ())" ile aynıdır, sorgunun etrafına sarılmasına gerek yoktur
Lucas

0

Öyleyse, uid'in Benzersiz Tanımlayıcı (Kılavuz) olduğunu doğru bir şekilde varsayıyor muyum? Bu sadece olası bir senaryo örneği mi yoksa bir dizi diziyle eşleşen bir kılavuz bulmaya gerçekten mi çalışıyorsunuz?

Bu doğruysa, tüm bu yaklaşımı gerçekten yeniden düşünmek isteyebilirsiniz, bu gerçekten kötü bir fikir gibi görünüyor. Muhtemelen bir Kılavuzu bir Kılavuzla eşleştirmeye çalışmalısınız

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

Açıkçası, "içerir" kullanarak bir dizge dizisini bir Kılavuzun içeriğiyle eşleştirmenin iyi bir fikir olacağı bir senaryo hayal edemiyorum. İlk olarak, Contains () Kılavuzdaki sayıların sırasını garanti etmez, böylece birden fazla öğeyi eşleştirme potansiyeline sahip olabilirsiniz. Kılavuzları bu şekilde karşılaştırmaktan bahsetmemek, doğrudan yapmaktan çok daha yavaş olacaktır.


0

Bunu tam tersi şekilde yazmalısınız, ayrıcalıklı kullanıcı kimliği listenizin bu tablo satırındaki kimliği içerdiğini kontrol edin:

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

LINQ burada oldukça parlak davranır ve bunu iyi bir SQL ifadesine dönüştürür:

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'

temel olarak 'search' dizisinin içeriğini sql sorgusuna yerleştirir ve SQL'de 'IN' anahtar kelimesi ile filtrelemeyi yapar.


2100'den fazla parametreniz olmadığı sürece bu iyi çalışır.
jpierson

0

Bir çözüm bulmayı başardım, ancak DB'den tüm sonuçları döndürecek olan AsEnumerable () kullanmayı gerektirdiği için harika bir çözüm değil, neyse ki tabloda sadece 1k kayıt var, bu yüzden gerçekten farkedilemez, ama işte gidiyor .

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;

Orijinal yazım şöyle:

Tersini nasıl yaparsınız? Varlık çerçevesinde aşağıdakine benzer bir şey yapmak istiyorum.

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

İstediğim şey, FullName'in `` arama '' içindeki tüm öğeleri içerdiği tüm kullanıcıları bulmak. Hepsi benim için çalışmayan bir dizi farklı yol denedim.

Ben de denedim

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

Bu sürüm, yalnızca arama dizisindeki son öğeyi içerenleri bulur.


0

Bulduğum en iyi çözüm devam etmek ve SQL'de aşağıdaki gibi sonuçları üreten bir Tablo Değerli İşlev oluşturmaktı:

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')

Ardından, işlevi LINQ.dbml tasarımcınıza sürükleyin ve diğer nesnelerinizi yaptığınız gibi çağırın. LINQ, depolanan işlevinizin sütunlarını bile bilir. Bunu şöyle seslendiriyorum:

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

İnanılmaz derecede basit ve uygulamada SQL ve LINQ'nun gücünü gerçekten kullanıyor ... ve tabii ki, aynı etkiler için istediğiniz herhangi bir tablo değerli işlevi oluşturabilirsiniz!


0

Gerçekten yapmak istediğiniz şeyin şuna inanıyorum: iki veritabanınız olduğunu ve ortak bir ürün tablosuna sahip olduklarını bir senaryo hayal edelim.

içerir yöntemini kullanmak bunu yapmak için çok karmaşık olur, yaptığımız şey bir kesişimdir ve bunun için kesişim adı verilen bir yöntem vardır.

msdn'den bir örnek: http://msdn.microsoft.com/en-us/vcsharp/aa336761.aspx#intersect1

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

Bence ihtiyacınız olan şey kavşakla kolayca çözülür


0

Bu uzantı yöntemini kontrol edin:

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

Deneyin:

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

Bu kod soruyu yanıtlayabilirken, sorunu nasıl ve / veya neden çözdüğüne ilişkin ek bağlam sağlamak , yanıtın uzun vadeli değerini artıracaktır.
Sistem

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

SO'ya geliyoruz. Lütfen "yalnızca kod" yanıtları vermeyin. Bunun sorunu nasıl çözdüğüne ve diğer 21 cevapta henüz ele alınmadığına dair biraz açıklama ekleyebilir misiniz?
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()) 
  }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.