What are the names given to these 2 LINQ expressions - linq

I'm trying to find the correct names for these 2 "types" of coding expressions in LINQ so that I can refer to them correctly. I want to say that the first is called "Fluent Style"?
var selectVar = arrayVar.Select( (a,i) => new { Line = a });
var selectVar =
from s in arrayVar
select new { Line = s };

First - calling an extension method.
This style of coding is called "fluent interface" as you mentioned.
Second method is called language integrated query

The name of the second form is "query comprehesion syntax", which the compiler translates into the first form.

The first isn't even really LINQ, it's a lambda expression, with a type invariant object created.
(a) => new { blah = b}
The second is a LINQ query filling an on the fly class that has a property Line.
There is no hashrocket operator in this one, so this one is just plain old linq.

Related

Need linq query

I have 3 fields(Name, Code, displayNmae) in the list, here I need to get a list as output in which I get all the fields but need to split displayname field by colon and then add list again for each splitted value which is display name.
Hence in output list I will have the 5 row as total display name are 5 in 2 rows.
Need the linq query for this problem.
Name Code displayName
Napkins_tableware - Napkins and tableware - 3_ply:conventional_napkins
hand-towel - Hand and Towel - 2_ply:towel roll:coloured
Output should be like this :
Name Code displayName
Napkins_tableware - Napkins and tableware - 3_ply
Napkins_tableware - Napkins and tableware - conventional_napkin
hand-towel - Hand and Towel - 2_ply
hand-towel - Hand and Towel - towel roll
hand-towel - Hand and Towel - coloured
Solution which I tried in C#
foreach(ProductDetailsWithFilters qs in CategoryProductList())
{
foreach(string friendlyname in qs.displayName.Split(':'))
{
qs.displayName = friendlyname;
tempCategoryProductList.Add(qs);
}
}
If you're translating to LINQ, when you have nested foreach loops those correspond to 'from' clauses in query syntax (or in dot syntax, subsequent ones become SelectMany, see below.) The following should be close to what you want:
var query =
from qs in CategoryProductList()
from friendlyName in qs.displayName.Split(':')
select new ProductDetailsWithFilters(qs.Code, qs.Category, friendlyName);
Note: Because functional programming should be side-effect-free, it's better to select a new instance ProductDetailsWithFilters than it is to modify the existing one in your query. My presumption is that you can call a constructor to build a new one of these.
For you to modify the existing property like your loop implementation does, you would have to iterate over the result -- LINQ doesn't provide such a thing in the framework. Such side-effects often lead to hard-to-find bugs.
To do the equivalent of the above query with a SelectMany and dot-syntax:
var query = CategoryProductList()
.SelectMany(
qs => qs.DisplayName.Split(':'),
(qs, friendlyName) => new ProductDetailsWithFilters(qs.Code, qs.Category, friendlyName));
Both lead to functionally identical code. In this case, I tend to prefer the query-syntax over the dot-syntax partly because because there are several SelectMany overloads and handling the projection involves repeating the variables across both lambda expressions. If you had another "from" to add, the query-syntax hides the management of 'transparent identifiers' that you would otherwise have to deal with in dot-syntax equivalent code. Whatever your preference, you now have both.
It's worth noting that queries are lazy -- they do nothing until you iterate over their result. So it's really what you do with the result from here that is the interesting part - store it .ToList(), directly data-bind it to a UI, use it to service a web-API, etc...

Linq to XML + chaining expressions

I have the following code that's repeated:
var ccaNumber = (from r in xDoc.Elements("ResultSet").Elements("DataRow")
where Convert.ToInt32(r.Element("PaymentPlanNumber").Value) == payPlan.OrderNumber
Ideally, I want to create the above as an expression then add my clause to the end of it.
So, I created the expression as follows:
Expression currExp = from r in xDoc.Elements("ResultSet").Elements("DataRow")
where Convert.ToInt32(r.Element("PaymentPlanNumber").Value) == payPlan.OrderNumber;
I now want to combine them:
var ccaNumber = (currExp select r.Element("CreditCardAuthorityNumber").Value).FirstOrDefault();
However I now get the following error:
Invalid expression term ')'
Any suggestions?
ta,
yogi
I think you are mixing things up here.
What you can do is:
var items = from r in xDoc.Elements("ResultSet").Elements("DataRow")
where Convert.ToInt32(r.Element("PaymentPlanNumber").Value) == payPlan.OrderNumber
select r;
This declares items as a Enumerable of elements that match your Where-Condition.
And then you can use those defined items like this:
var ccaNumber = items.Select(item=>item.Element("CreditCardAuthorityNumber").Value).FirstOrDefault();
However, this is all utilising lazy evaluation and you need to take care of multiple enumerations here. Here is a pretty indepth explanaition that is way better than my sh*tty english.
When adding to an existing expression, you need to use the lambda syntax, not the Linq syntax:.
Try:
var ccaNumber = (currExp
.Select(r=>r.Element("CreditCardAuthorityNumber").Value))
.FirstOrDefault();

Create an object if one is not found

How do I create an object if one is not found? This is the query I was running:
#event_object = #event_entry.event_objects.find_all_by_plantype('dog')
and I was trying this:
#event_object = EventObject.new unless #event_entry.event_objects.find_all_by_plantype('dog')
but that does not seem to work. I know I'm missing something very simple like normal :( Thanks for any help!!! :)
find_all style methods return an array of matching records. That is an empty array if no matching records are found. And an empty is truthy. Which means:
arr = []
if arr
puts 'arr is considered turthy!' # this line will execute
end
Also, the dynamic finder methods (like find_by_whatever) are officially depreacted So you shouldn't be using them.
You probably want something more like:
#event_object = #event_entry.event_objects.where(plantype: 'dog').first || EventObject.new
But you can also configure the event object better, since you obviously want it to belong to #event_entry.
#event_object = #event_entry.event_objects.where(plantype: 'dog').first
#event_object ||= #event_entry.event_objects.build(plantype: dog)
In this last example, we try to find an existing object by getting an array of matching records and asking for the first item. If there are no items, #event_object will be nil.
Then we use the ||= operator that says "assign the value on the right if this is currently set to a falsy value". And nil is falsy. So if it's nil we can build the object form the association it should belong to. And we can preset it's attributes while we are at it.
Why not use built in query methods like find_or_create_by or find_or_initialize_by
#event_object = #event_entry.event_objects.find_or_create_by(plantype:'dog')
This will find an #event_entry.event_object with plantype = 'dog' if one does not exist it will then create one instead.
find_or_initialize_by is probably more what you want as it will leave #event_object in an unsaved state with just the association and plantype set
#event_object = #event_entry.event_objects.find_or_initialize_by(plantype:'dog')
This assumes you are looking for a single event_object as it will return the first one it finds with plantype = 'dog'. If more than 1 event_object can have the plantype ='dog' within the #event_entry scope then this might not be the best solution but it seems to fit with your description.

How do I create a compound multi-index in rethinkdb?

I am using Rethinkdb 1.10.1 with the official python driver. I have a table of tagged things which are associated to one user:
{
"id": "PK",
"user_id": "USER_PK",
"tags": ["list", "of", "strings"],
// Other fields...
}
I want to query by user_id and tag (say, to find all the things by user "tawmas" with tag "tag"). Starting with Rethinkdb 1.10 I can create a multi-index like this:
r.table('things').index_create('tags', multi=True).run(conn)
My query would then be:
res = (r.table('things')
.get_all('TAG', index='tags')
.filter(r.row['user_id'] == 'USER_PK').run(conn))
However, this query still needs to scan all the documents with the given tag, so I would like to create a compound index based on the user_id and tags fields. Such an index would allow me to query with:
res = r.table('things').get_all(['USER_PK', 'TAG'], index='user_tags').run(conn)
There is nothing in the documentation about compound multi-indexes. However, I
tried to use a custom index function combining the requirements for compound
indexes and multi-indexes by returning a list of ["USER_PK", "tag"] pairs.
My first attempt was in python:
r.table('things').index_create(
'user_tags',
lambda each: [[each['user_id'], tag] for tag in each['tags']],
multi=True).run(conn)
This makes the python driver choke with a MemoryError trying to parse the index function (I guess list comprehensions aren't really supported by the driver).
So, I turned to my (admittedly, rusty) javascript and came up with this:
r.table('things').index_create(
'user_tags',
r.js(
"""(function (each) {
var result = [];
var user_id = each["user_id"];
var tags = each["tags"];
for (var i = 0; i < tags.length; i++) {
result.push([user_id, tags[i]]);
}
return result;
})
"""),
multi=True).run(conn)
This is rejected by the server with a curious exception: rethinkdb.errors.RqlRuntimeError: Could not prove function deterministic. Index functions must be deterministic.
So, what is the correct way to define a compound multi-index? Or is it something
which is not supported at this time?
Short answer:
List comprehensions don't work in ReQL functions. You need to use map instead like so:
r.table('things').index_create(
'user_tags',
lambda each: each["tags"].map(lambda tag: [each['user_id'], tag]),
multi=True).run(conn)
Long answer
This is actually a somewhat subtle aspect of how RethinkDB drivers work. So the reason this doesn't work is that your python code doesn't actually see real copies of the each document. So in the expression:
lambda each: [[each['user_id'], tag] for tag in each['tags']]
each isn't ever bound to an actual document from your database, it's bound to a special python variable which represents the document. I'd actually try running the following just to demonstrate it:
q = r.table('things').index_create(
'user_tags',
lambda each: print(each)) #only works in python 3
And it will print out something like:
<RqlQuery instance: var_1 >
the driver only knows that this is a variable from the function, in particular it has no idea if each["tags"] is an array or what (it's actually just another very similar abstract object). So python doesn't know how to iterate over that field. Basically exactly the same problem exists in javascript.

linq expression for string array always results in "The name 'result' does not exist in the current context"

I'm trying to get certain keys from the Request.Form.AllKeys string array by using the following:
var result = keys.Where(key => key.StartsWith("added"));
The result is "The name 'result' does not exist in the current context" no matter what I do.
I've also tried:
var result = (from keys in Request.Form.AllKeys
where keys.StartsWith("added")
select keys).ToArray();
Same thing.
I'm new to Linq and Lambda expressions and all, so please forgive the ignorance.
Regards,
Jacques
I found the answer to my question: Delayed execution.
When I actually executed the code and then followed it up by using result.Any() the expression was executed and turned out the correct results.

Categories

Resources