Using the query expression style, the let clause can be easily written. My question is how to use the dot notation style to write a let clause.
Essentially it's a Select (in most cases) which introduces a transparent identifier - via an anonymous type which encapsulates all the currently specified range variables. For example, this query:
string[] names = { "Jon", "Mark" };
var query = from name in names
let length = name.Length
where length > 3
select name + ": " + length;
is translated into something like this:
var query = names.Select(name => new { name, length = name.Length })
.Where(z => z.length > 3)
.Select(z => z.name + ": " z.length);
Related
How can I write the following code in a more elegant way using java8?
String query = "select device, manufacturer, type from devices where username = ?";
boolean found = false;
if (deviceTypes.stream().filter(t -> "typeA".equals(t)).findFirst().isPresent()) {
query += " AND type like 'A%'";
found = true;
}
if (deviceTypes.stream().filter(t -> "typeB".equals(t)).findFirst().isPresent()) {
if (found) {
query += " OR ";
} else {
query += " AND ";
}
query += " type like 'B%'";
}
If in the device types there are both A and B, the query should contain both with OR.
Example:-
deviceTypes="A,B" --> query condition => AND type like 'A%' OR type like 'B%';
Example:-
deviceTypes="B" --> query condition => AND type like 'B%';
thanks a lot
You may store the association between the deviceTypes strings and the predicate expressions in a map like
final Map<String,String> typeToExpression
= Map.of("typeA", "type like 'A%'", "typeB", "type like 'B%'");
Or use static final. This factory method requires Java 9+ but constructing a map should be straight-forward.
Then, one solution would be
String query = "select device, manufacturer, type from devices where username = ?";
query += deviceTypes.stream()
.map(typeToExpression::get).filter(Objects::nonNull)
.reduce((a, b) -> a + " OR " + b)
.map(" AND "::concat).orElse("");
which produces a string similar to your approach. But considering the operator precedence, I suppose, you might rather want
String query = "select device, manufacturer, type from devices where username = ?";
query += deviceTypes.stream()
.map(typeToExpression::get).filter(Objects::nonNull)
.reduce((a, b) -> "(" + a + " OR " + b + ")")
.map(" AND "::concat).orElse("");
This is optimized for your described case of having a rather small number of possible conditions, especially for two or less. But we can still reduce some of the largest string concatenation steps with only slightly more code.
final String baseQ = "select device, manufacturer, type from devices where username = ?";
String query = deviceTypes.stream()
.map(typeToExpression::get).filter(Objects::nonNull)
.reduce((a, b) -> "(" + a + " OR " + b + ")")
.map(cond -> baseQ + " AND " + cond).orElse(baseQ);
Here, baseQ is a compile-time constant, which in turn makes baseQ + " AND " a compile-time constant too which is combined with the predicate(s) in one step. If there is only one matching predicate, only one string concatenation will be performed. Further, if no matching predicate has been found, this evaluates to the already existing constant baseQ string.
But if you expect large numbers of predicates, a different approach should be used, optimized for larger numbers of elements, at the expense of the small number cases:
final String baseQ = "select device, manufacturer, type from devices where username = ?";
String query = deviceTypes.stream()
.map(typeToExpression::get).filter(Objects::nonNull)
.collect(
() -> new StringJoiner(" OR ", baseQ + " AND (", ")").setEmptyValue(baseQ),
StringJoiner::add,
StringJoiner::merge)
.toString();
Unlike the other approaches this will always put brackets around the predicates, even if there is one, but it will still only use that single pair of brackets when there are three or more. It avoids performing multiple string concatenations in a row by letting the StringJoiner do the entire work.
IList<Item> items = new List<Item>();
items.Add(new Item
{
tag = "{" + Ann + "}",
value = "Anny"
});
items.Add(new Item
{
tag = "{" + John + "}",
value = "Johnny"
});
How can I use Linq to select tag with {John} and replace value with "Jane"?
LINQ is, as the name suggests, more of a query tools. So you can get specific item(s) that you want to modify from a collection using LINQ, but the modification itself is out-of-scope for LINQ.
Assuming that there is always maximum one match to your criteria, you can do as follows :
var john = items.FirstOrDefault(o => o.tag == "{John}");
if(john != null)
{
john.value = "Jane";
}
Otherwise, you can use LINQ Where(o => o.tag == "{John}") to get the target items for modification. But then you'll need to iterate through the result to actually update the value of each matched item.
items.Where(o => o.tag == "{"+John+"}").ToList().ForEach(item =>{
item.value = "Jane";
});
Here is working fiddle
I am new to LINQ, and I wish to convert from one datatype to another in C#, as well as concatenate a string. How would I accomplish this?
For example, what would the SQL statement
SELECT IPv4 = CONVERT(varchar(3), IPv4_octet1) + '.' +
CONVERT(varchar(3), IPv4_octet2) + '.' +
CONVERT(varchar(3), IPv4_octet3) + '.' +
CONVERT(varchar(3), IPv4_octet4) FROM table;
be in LINQ? (The IPv4_octet's are stored as tinyints in the SQL table.)
In this case I suspect you could just write:
var query = data.Select(x => x.IpV4Octet1 + "." +
x.IpV4Octet2 + "." +
x.IpV4Octet3 + "." +
x.IpV4Octet4);
More generally you'd call ToString, e.g.:
// You wouldn't want to actually do this, but...
var query = data.Select(x => x.IpV4Octet1.ToString() + x.IpV4Octet4.ToString());
If you want more control, and you're not using the result in the rest of the query, you may well want to do the formatting on the .NET side - simply use AsEnumerable when you've selected all the information you want from the database, and then do the rest in LINQ to Objects. For example:
var query = db.Select(x => new { x.HostName, x.IpV4Octet1, x.IpV4Octet2,
x.IpV4Octet3, IpV4Octet4 })
.AsEnumerable() // Switch to LINQ to Objects for rest of query
.Select(x => new { x.HostName,
Address = string.Format("{0}.{1}.{2}.{3}"),
x.IpV4Octet1,
x.IpV4Octet2,
x.IpV4Octet3,
x.IpV4Octet4) });
try this:
string ipv4 = string.Join('.',octets.Select(o => o.ToString()).ToArray());
I want to convert this LINQ code
var x = from nm in names
select MyClass.SomeMethod(nm).TrimStart(',');
foreach (var vv in x)
{
// I want to group and count different types of vv here
}
to use shorter syntax, one where they do x => x in LINQ. I also want to group and count 'vv' (there could be number of similar vv's)
Well, the "dot notation" or "fluent notation" for the above is:
var x = names.Select(nm => MyClass.SomeMethod(nm).TrimStart(','));
For grouping:
var x = names.Select(nm => MyClass.SomeMethod(nm).TrimStart(','));
.GroupBy(vv => vv,
(key, group) => new { Key = key, Count = group.Count() });
Something like this?
MyClass.SomeMethod(names).TrimStart(',')
.GroupBy(x => x.vv)
.ToList()
.ForEach(x => Console.WriteLine(x.Key + ": " + x.Count()));
I want to get a collection of Product entities where the product.Description property contains any of the words in a string array.
It would look something like this (result would be any product which had the word "mustard OR "pickles" OR "relish" in the Description text):
Dim products As List(Of ProductEntity) = New ProductRepository().AllProducts
Dim search As String() = {"mustard", "pickles", "relish"}
Dim result = From p In products _
Where p.Description.Contains(search) _
Select p
Return result.ToList
I already looked at this similar question but couldn't get it to work.
Since you want to see if search contains a word which is contained in the description of p you basically need to test for each value in search if it is contained in the description of p
result = from p in products
where search.Any(val => p.Description.Contains(val))
select p;
This is c# syntax for the lambda method since my vb is not that great
Dim result = From p in products _
Where search.Any(Function(s) p.Description.Contains(s))
Select p
You can use a simple LINQ query, if all you need is to check for substrings:
var q = words.Any(w => myText.Contains(w));
// returns true if myText == "This password1 is weak";
If you want to check for whole words, you can use a regular expression:
Matching against a regular expression that is the disjunction of all the words:
// you may need to call ToArray if you're not on .NET 4
var escapedWords = words.Select(w => #"\b" + Regex.Escape(w) + #"\b");
// the following line builds a regex similar to: (word1)|(word2)|(word3)
var pattern = new Regex("(" + string.Join(")|(", escapedWords) + ")");
var q = pattern.IsMatch(myText);
Splitting the string into words with a regular expression, and testing for membership on the words collection (this will get faster if you use make words into a HashSet instead of a List):
var pattern = new Regex(#"\W");
var q = pattern.Split(myText).Any(w => words.Contains(w));
In order to filter a collection of sentences according to this criterion all you have to do its put it into a function and call Where:
// Given:
// bool HasThoseWords(string sentence) { blah }
var q = sentences.Where(HasThoseWords);
Or put it in a lambda:
var q = sentences.Where(s => Regex.Split(myText, #"\W").Any(w => words.Contains(w)));
Ans From => How to check if any word in my List<string> contains in text by #R. Martinho Fernandes