Is there a way I can do something like this with Lambda expressions?
responses.Add(sr).Where(v.Responses.TryGetValue(v.responseType, out sr));
I want to use lambda expressions or a ternary operator instead of a typical if expression.
NB:
responses is a List<string> type.
v.Responses is a Dictionary of <enum ResponseType, string>
v is some object
sr is a string.
What you want to do is:
string sr;
if (v.Responses.TryGetValue(v.responseType, out sr))
responses.Add(sr);
There is no way to ease the syntax and get the same performance.
But you could do:
responses.AddRange( v.Responses.Where( p => p.Key == v.responseType )
.Select( p => p.Value ) );
You may want to think about what the last one is doing, because it is kind of stupid...
EDIT: the reason why it is stupid is because the last expression translates into:
foreach(var pair in v.Responses)
{
if (pair.Key == v.responseType)
responses.Add(pair.Value);
}
So if your ResponseType enumeration had 6 million entries, the program would iterate over the entire set of keys to find the correct entry. In your case, since you already know the key, you should use v.Responses[key] as it is extremely fast (see in which cases dictionaries must be use).
LINQ is not supposed to modify collections.
Couldn't you simply do something like this:
string sr;
if(v.Responses.TryGetValue(v.responseType, out sr))
responses.Add(sr);
If I understand your question correctly, this might do what you're looking for.
Based on your example code, I'm assuming that your object "v" contains a field named "responseType" of type RepsonseType.
var responses = v.Responses
.Where(r => r.Key == v.responseType)
.Select(r => r.Value)
.ToList();
Related
I have the following two LINQ statements which set different values in the same item in a list
List<MyClass> myList = GetList();
myList.Where(x => x.Name == "someName").Select(x => x.MyArray = someList.ToArray()).ToList();
myList.Where(x => x.Name == "someName").Select( x => x.AnotherValue = GetValue()).ToList();
Is it possible to combine this so both are set in the one expression?
myList
.Where(x => x.Name == "someName")
.ToList()
.ForEach(x => {
x.MyArray = someList.ToArray();
x.AnotherValue = GetValue();
});
Why are you calling ToList() at the end of each of those expressions and discarding the result?
Also, Jon Skeet is right that this is an abuse of LINQ, and especially so in your original form: It's explicit that LINQ expressions aren't even necessarily expected to be fully enumerated. The fact that you needed those ToList() calls to make anything happen should have given you a grave and queasy sense that you were misusing a language feature. When you have to do something weird to use your chosen construct instead of the usual way of doing it, finish getting it to work (because weird is cool), and then go back and redo it the boring, lame way before you check it in.
What advantage do you see in the LINQ + ForEach() version above, compared to this version?
foreach (var x in myList.Where(x => x.Name == "someName"))
{
x.MyArray = someList.ToArray();
x.AnotherValue = GetValue();
}
The old-style loop version is shorter, instantly understandable because it's the default idiom, and IMO cleaner. You don't have to do everything with LINQ.
N.B., ForEach() isn't LINQ; it's a member of List<T>. That's why you have to call ToList() to use it.
Just use the lambda operator to pass an entire lambda expression defined inside a
{...} block:
myList.Where(x => x.Name == "someName").Select(x => { x.MyArray = someList.ToArray(); x.AnotherValue = GetValue(); return x;}).ToList();
I need do a filter that request data with a parameter included in a list.
if (filter.Sc.Count > 0)
socios.Where(s => filter.Sc.Contains(s.ScID));
I try on this way but this not work, I tried also...
socios.Where( s => filter.Sc.All(f => f == s.ScID));
How I can do a filter like this?
socios.Where(s => filter.Sc.Contains(s.ScID));
returns a filtered query. It does not modify the query. You are ignoring the returned value. You need something like:
socios = socios.Where(s => filter.Sc.Contains(s.ScID));
but depending on the type of socios the exact syntax may be different.
In addition to needing to use the return value of your LINQ .Where(), you have a potential logic error in your second statement. The equivalent logic for a .Contains() is checking if Any of the elements pass the match criteria. In your case, the second statement would be
var filteredSocios = socios.Where( s => filter.Sc.Any(f => f == s.ScID));
Of course if you can compare object-to-object directly, the .Contains() is still adequate as long as you remember to use the return value.
I have below legacy code in my application and would like to optimize it. arrayOfAttrValue has unique attributes. Can I use LINQ to acheive the loop optimization? If so then can you please show me how?
foreach (AttrValue attr in arrayOfAttrValue)
{
switch(attr.Attribute)
{
case Constants.Gender
mymodel.Gender = attr.Value;
break;
case Constants.Identifier
mymodel.AppIdentifier = attr.Value;
break;
}
}
My intention is not necessarily to use LINQ only. Any other way to minimize the loop would also help.
Thanks.
No, you can't do it in "true" LINQ because LINQ is about producing new objects from old objects. Here mymodel is a preexisting object that you want to modify.
You could use the Array.ForEach or the List.ForEach but
They aren't "true" LINQ and
The resulting code would be equivalent (a little slower because there would be a delegate)
Still, the downvoter probably wanted some LINQ, so I'll give some LINQ:
arrayOfAttrValue.All(attr => {
mymodel.Gender = attr.Attribute == Constants.Gender ? attr.Value : mymodel.Gender;
mymodel.AppIdentifier = attr.Attribute == Constants.Identifier ? attr.Value : mymodel.AppIdentifier;
return true;
});
One less line, ignoring the {} lines.
You have list of attributes, which represent key-value pairs. Natural way to keep such data structures is a dictionary. So, convert your input data format to dictionary:
var attributes = arrrayOfAttrValue.ToDictionary(a => a.Attribute, a => a.Value);
Or if each attribute is not unique in your array, dictionary creation will be more difficult, but that's data format you have. In order to make working with your data easier you should convert them to handy format:
var attributes = arrayOfAttrValue
.GroupBy(a => a.Attribute)
.ToDictionary(g => g.Key, g => g.Select(a => a.Value).Last());
After creating attributes dictionary, you can simply check if you have value for attribute and assign that value to model property. Attributes retrieving now simple and clear for any reader:
if (attributes.ContainsKey(Constants.Gender))
model.Gender = attributes[Constants.Gender];
if (attributes.ContainsKey(Constants.Identifier))
model.AppIdentifier = attributes[Constants.Identifier];
No need to do the loop manually in code, you can do it simply with .LastOrDefault():
mymodel.Gender = arrayOfAttrValue
.Where(attr => attr.Attribute == Constants.Gender)
.Select(attr => attr.Value).LastOrDefault() ?? mymodel.Gender;
mymodel.AppIdentifier = arrayOfAttrValue
.Where(attr => attr.Attribute == Constants.Identifier)
.Select(attr => attr.Value).LastOrDefault() ?? mymodel.AppIdentifier;
The ?? mymodel.Gender makes sure we're not setting it to Default(T) (i.e. null) in a situation where it was otherwise set to a value previously. This then matches the functional logic of your initial question.
Doing it this way makes it very clear what you are trying to do. Of course this approach means that you're looping over the array twice, however if your array is actually an array then this performance cost will be very small.
If you still have performance issues with this then you probably want to consider using a better data structure than an arrayOfAttrValue (something that is index accessable by Attribute such as a Dictionary<,>).
I have a function like so
public List<Entry> GetEntriesForSlider(int first, int max, List<string> NameLetters)
{
//Some code
}
Inside this code, I want to search along a database, to return every result that has the firstname starting with a letter within the NameLetters.
So if I pass in the array NameLetters = ["a","b","c"]
Then it will return results such as
Amy
Bert
Aaron
Chris
It should be noted that I am ideally looking to use some sort of linq statement such as...
entries.Where(x => x.FirstName.StartsWith(partofArray));
If at all possible.
EDIT : I previously had the following :
var entries = _repository.All<Entry>().Skip(first).Take(max);
if (NameLetters != null && NameLetters.Count > 0)
entries = entries.Where(x => NameLetters.Contains(x.FirstName[0].ToString()));
But what I found was, it enumerated the query (I think) before running the where statement. Possibly because trying to access the first letter of firstname (Or the ToString).
If you're just looking to match the first letter try:
entries.Where(x => partofArray.Contains(x.FirstName[0]));
If you need to worry about null or empty strings a safer version would be:
entries.Where(x =>
!string.IsNullOrEmpty(x.FirstName) &&
partofArray.Contains(x.FirstName[0])
);
If you want to use variable-length strings try:
entries.Where(x =>
partofArray.Any( p=> x.FirstName.StartsWith(p))
);
Perhaps you should take a look at predicate builder.
Then something like
IQueryable<Entry> GetThingsThatBeginWithA(String[] prefixes)
{
var predicate = PredicateBuilder.False<Entry>();
foreach (String prefix in prefixes)
predicate = predicate.Or(p => p.FirstName.StartsWith(prefix));
return database.Entries.Where(predicate);
}
This query should correctly compile to a single query to the SQL store.
Update: It can also be done without predicate builder, but I find that working with expression trees without it is really tedious.
Here is what I currently have:
from s in domainThreads.Values
where (s.IsAvailable)
select s;
but I'm still learning Linq and believe that I can get it all on one line. Does the following look correct?
domainThreads.Values.Where(s => s.IsAvailable).Any();
Do I need the .Any()?
Any() returns a boolean indicating whether or not there are any entities in the given set.
The equivalent of your original LINQ expression would simply be:
domainThreads.Values.Where(s => s.IsAvailable)
The two are not equivalent.
The first returns all Values where s.IsAvailable.
The second returns whether there are any such values.
A correct conversion is:
domainThreads.Values.Where(s => s.IsAvailable)
Which translates to:
domainThreads.Values.Where(s => s.IsAvailable).Select(s => s)
Which is what the original query gets transformed to anyways.
You don't need the Any() -- that will return a bool indicating if any of elements satisfy the condition.
Instead, just do:
domainThreads.Values.Where(s => s.IsAvailable)
domainThreads.Values.Where(s => s.IsAvailable)
is enough.
Any() returns a bool value, but your original query returns a data set. So just use Where()
var result = domainThreads.Values.Where(s => s.IsAvailable);
Any() would be helpful when you just need ensure that at least single item satisfies a condition
Try this
var obj = domainThreads.Values.Where(s => s.IsAvailable == true).Select(o => o);
If you call Any() it returns bool which indicates that you have at least one item.
domainThreads.Values.Where(s => s.IsAvailable);
this expression is enough and it is equivalent to the LINQ statement.
Any() returns a boolean that is true if the result contains one or more items.
var elements = from s in domainThreads.Values
where (s.IsAvailable)
select s;
//elements now contains a list of objects.
This is equivalent to:
elements = domainThreads.Where(s => s.IsAvailable);
It looks but is not the same. The result is boolean and returns true if the collection contains any elements.
You could write something like this, but is it really worth the effort?
var result = domainThreads.Values.Where(s => s.IsAvailable).Select(s => s);
or shorter:
var result = domainThreads.Values.Where(s => s.IsAvailable);
EDIT: if you just want to have one line of code you can also write:
from s in domainThreads.Values where s.IsAvailable select s;
It's much more readable and generates to the same code in the end.