web-dev-qa-db-fra.com

Comment utiliser LINQ Contains (string []) au lieu de Contains (string)

J'ai une grande question.

J'ai une requête linq pour le dire qui ressemble simplement à ceci:

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

Les valeurs du tableau string[] seraient des nombres comme (1,45,20,10, etc ...)

la valeur par défaut pour .Contains est .Contains(string).

J'ai besoin de le faire à la place: .Contains(string[])...

EDIT: Un utilisateur a suggéré d'écrire une classe d'extension pour string[]. J'aimerais savoir comment, mais est-ce que quelqu'un est prêt à me diriger dans la bonne direction?

EDIT: L'uid serait aussi un nombre. C'est pourquoi il est converti en chaîne.

Aider quelqu'un?

89
SpoiledTechie.com

spoulson a presque raison, mais vous devez d'abord créer un List<string> à partir de string[]. En fait un List<int> serait mieux si uid est aussi int. List<T> prend en charge Contains(). Faire uid.ToString().Contains(string[]) impliquerait que l'uid en tant que chaîne contienne toutes les valeurs du tableau en tant que sous-chaîne ??? Même si vous aviez écrit la méthode d'extension, vous auriez tort de la comprendre.

[EDIT]

À moins que vous ne l'ayez modifié et écrit pour string[] comme le montre Mitch Wheat, vous pourrez alors ignorer l'étape de conversion.

[ENDEDIT]

Voici ce que vous voulez, si vous ne faites pas la méthode d'extension (à moins que vous ne possédiez déjà la collection d'uid potentiels en tant qu'ints - utilisez simplement List<int>() à la place). Cela utilise la syntaxe de méthode chaînée, ce qui, je pense, est plus propre, et effectue la conversion en int pour garantir que la requête peut être utilisée avec plus de fournisseurs.

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

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

Si vous cherchez vraiment à répliquer contient , mais pour un tableau, voici une méthode d'extension et un exemple de code d'utilisation:

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;
        }
    }
}
32
Jason Jackson

Essayez ce qui suit.

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

LINQ dans .NET 4.0 a une autre option pour vous; la méthode .Any ();

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

Ou si vous avez déjà les données dans une liste et préférez l'autre format Linq :)

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

Que diriez-vous:

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

C'est une réponse tardive, mais je crois que cela reste utile .
J'ai créé le paquet nuget NinjaNye.SearchExtension qui peut aider à résoudre ce problème:

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

Vous pouvez également rechercher plusieurs propriétés de chaîne

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

Ou effectuez une RankedSearch qui renvoie IQueryable<IRanked<T>>, qui inclut simplement une propriété indiquant le nombre de fois que les termes de recherche sont apparus:

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

Il existe un guide plus complet sur la page des projets GitHub: https://github.com/ninjanye/SearchExtensions

J'espère que cela aide les futurs visiteurs

2
NinjaNye

Voici un exemple de méthode d'écriture d'une méthode d'extension (note: je ne l'utiliserais pas pour les très grands tableaux; une autre structure de données serait plus appropriée ...):

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;
        }
    }
}
2
Mitch Wheat

Méthode d'extension Linq. Travaillera avec n'importe quel objet IEnumerable:

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

Usage:

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

bool Array2ItemsInArray1 = List1.ContainsAny(List2);
1
kravits88

Je crois que vous pourriez aussi faire quelque chose comme ça.

from xx in table
where (from yy in string[] 
       select yy).Contains(xx.uid.ToString())
select xx
1
ctrlShiftBryan
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
Hari Lakkakula

Essayer:

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

Alors, est-ce que je suppose correctement que uid est un identifiant unique (Guid)? S'agit-il simplement d'un exemple de scénario possible ou essayez-vous réellement de trouver un guid correspondant à un tableau de chaînes?

Si cela est vrai, vous voudrez peut-être vraiment repenser toute cette approche, cela semble être une très mauvaise idée. Vous devriez probablement essayer de faire correspondre un Guid à un Guid

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

Honnêtement, je ne peux pas imaginer un scénario où faire correspondre un tableau de chaînes en utilisant "contient" au contenu d'un Guid serait une bonne idée. D'une part, Contains () ne garantit pas l'ordre des nombres dans le Guid afin que vous puissiez potentiellement faire correspondre plusieurs éléments. Sans parler de comparer les astuces de cette façon, ce serait beaucoup plus lent que de le faire directement.

0
justin.m.chase

La meilleure solution que j'ai trouvée consistait à créer une fonction à valeur de table en SQL qui produirait les résultats, tels que:

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

Ensuite, il vous suffit de faire glisser la fonction dans votre concepteur LINQ.dbml et de l’appeler comme vous le faites avec vos autres objets. Le LINQ connaît même les colonnes de votre fonction stockée. Je l'appelle comme ça ::

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

Incroyablement simple, il exploite réellement la puissance de SQL et de LINQ dans l'application ... et vous pouvez bien sûr générer n'importe quelle fonction table que vous voulez pour les mêmes effets!

0
beauXjames

Je crois que ce que vous voulez vraiment faire est: imaginons un scénario où vous avez deux bases de données et qui ont un tableau de produits en commun Et vous voulez sélectionner des produits dans le tableau "A" que cet identifiant a en commun avec le "B"

utiliser la méthode contient serait trop compliqué pour le faire. Ce que nous faisons est une intersection, et il existe une méthode appelée intersection pour cela.

un exemple tiré de msdn: http://msdn.Microsoft.com/en-us/vcsharp/aa336761.aspx#intersect1

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

Je pense que ce dont vous avez besoin est facilement résolu avec l'intersection

0
Lucas Cria
from xx in table
where xx.uid.Split(',').Contains(string value )
select xx
0
user1119399

Vous devriez l'écrire dans l'autre sens, en vérifiant que votre liste d'identifiants d'utilisateurs privilégiés contient l'identifiant sur cette ligne de la table:

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

LINQ se comporte ici très bien et le convertit en une bonne instruction SQL:

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'

qui incorpore fondamentalement le contenu du tableau 'search' dans la requête SQL et effectue le filtrage avec le mot clé 'IN' en SQL.

0
Gorkem Pacaci

Vérifiez cette méthode d'extension:

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
ron.camaron

J'ai réussi à trouver une solution, mais pas une excellente solution car elle nécessite l'utilisation de AsEnumerable (), qui renvoie tous les résultats de la base de données. Heureusement, je n'ai que 1k enregistrements dans le tableau. Ce n'est donc pas vraiment perceptible. .

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;

Mon article d'origine suit:

Comment faites-vous l'inverse? Je veux faire quelque chose comme ce qui suit dans le cadre d'entité.

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

Ce que je veux, c'est trouver tous les utilisateurs où leur nom complet contient tous les éléments de la recherche. J'ai essayé différentes méthodes, toutes ne fonctionnant pas pour moi.

J'ai aussi essayé

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

Cette version ne trouve que ceux qui contiennent le dernier élément du tableau de recherche.

0
Brett Ryan