Reputation: 4440
This is a cosmetics issue, it is syntactical sugar only, just because I want to do it. But basically I have a lot of code that reads like this ... I am using a dynamic
for the sheer purpose of time saving and example.
var terms = new List<string> {"alpha", "beta", "gamma", "delta", "epsilon", "rho"};
var list = new List<dynamic> {
new {
Foo = new List<string> {
"alpha",
"gamma"
}
}
};
var result = list
.Where(
n => n.Foo.Contains(terms[0]) ||
n.Foo.Contains(terms[1]) ||
n.Foo.Contains(terms[2]) ||
n.Foo.Contains(terms[3]) ||
n.Foo.Contains(terms[4]) ||
n.Foo.Contains(terms[5]))
.ToList();
Obviously this is a ludicrous hyperbole for the sheer sake of example, more accurate code is ...
Baseline =
Math.Round(Mutations.Where(n => n.Format.Is("Numeric"))
.Where(n => n.Sources.Contains("baseline") || n.Sources.Contains("items"))
.Sum(n => n.Measurement), 3);
But the basic point is that I have plenty of places where I want to check to see if a List<T>
(usually List<string>
, but there may at times be other objects. string
is my present focus though) contains any of the items from another List<T>
.
I thought that using .Any()
would work, but I actually haven't been able to get that to function as expected. So far, only excessive "||"
is all that yields the correct results.
This is functionally fine, but it is annoying to write. I wanted to know if there is a simpler way to write this out - an extension method, or a LINQ
method that perhaps I've not understood.
I am really aware that this may be a duplicate, but I am having a hard time figuring out the wording of the question to a level of accuracy that I can find duplicates. Any help is much appreciated.
Thank you very much for all of the help. This is my completed solution. I am using a dynamic
here just to save time on example classes, but several of your proposed solutions worked.
var terms = new List<string> {"alpha", "beta", "gamma", "delta", "epsilon", "rho"};
var list = new List<dynamic> {
new { // should match
Foo = new List<string> {
"alpha",
"gamma"
},
Index = 0
},
new { // should match
Foo = new List<string> {
"zeta",
"beta"
},
Index = 1
},
new { // should not match
Foo = new List<string> {
"omega",
"psi"
},
Index = 2
},
new { // should match
Foo = new List<string> {
"kappa",
"epsilon"
},
Index = 3
},
new { // should not match
Foo = new List<string> {
"sigma"
},
Index = 4
}
};
var results = list.Where(n => terms.Any(t => n.Foo.Contains(t))).ToList();
// expected output - [0][1][3]
results.ForEach(result => {
Console.WriteLine(result.Index);
});
Upvotes: 2
Views: 187
Reputation: 106906
If performance is an issue when using Any()
you can use a regular expression instead. Obviously, you should probably measure to make sure that regular expressions performs faster:
var terms = new List<string> { "alpha", "beta", "gamma", "delta", "epsilon", "rho" };
var regex = new Regex(string.Join("|", terms));
var result = list
.Where(n => regex.Match(n.Foo).Success);
This assumes that joining the terms to a list creates a valid regular expression but with simple words that should not be a problem.
One advantage of using a regular expression is that you can require that the terms are surrounded by word boundaries. Also, the predicate in the Where
clause may be easier to understand when compared to a solution using Contains
inside Any
.
Upvotes: 1
Reputation: 66479
You want to find out if Any
element in one collection exists within another collection, so Intersect
should work nicely here.
You can modify your second code snippet accordingly:
var sources = new List<string> { "baseline", "items" };
Baseline =
Math.Round(Mutations.Where(n => n.Format.Is("Numeric"))
.Where(n => sources.Intersect(n.Sources).Any())
.Sum(n => n.Measurement), 3);
Regarding the part of the docs you quoted for "Intersect":
Produces the set intersection of two sequences by using the default equality comparer to compare values.
Every object can be compared to an object of the same type, to determine whether they're equal. If it's a custom class you created, you can implement IEqualityComparer
and then you get to decide what makes two instances of your class "equal".
In this case, however, we're just comparing strings, nothing special. "Foo" = "Foo", but "Foo" ≠ "Bar"
So in the above code snippet, we intersect the two collections by comparing all the strings in the first collection to all the strings in the second collection. Whichever strings are "equal" in both collections end up in a resulting third collection.
Then we call "Any()" to determine if there are any elements in that third collection, which tells us there was at least one match between the two original collections.
Upvotes: 1
Reputation: 7075
I assume n.Foo is a string rather than a collection, in which case:
var terms = new List<string> { "alpha", "beta", "gamma", "delta", "epsilon", "rho" };
var list = (new List<string> { "alphabet", "rhododendron" })
.Select(x => new { Foo = x });
var result = list.Where(x => terms.Any(y => x.Foo.Contains(y)));
Upvotes: 1
Reputation: 726849
I thought that using
.Any()
would work, but I actually haven't been able to get that to function as expected.
You should be able to make it work by applying Any()
to terms
, like this:
var result = list
.Where(n => terms.Any(t => n.Foo.Contains(t)))
.ToList();
Upvotes: 4
Reputation: 53958
You could try this one:
var result = list.Where(terms.Contains(n.Foo))
.ToList();
Upvotes: 1