I have a list:
var _books = new List<int> {233,5,20};
And a ListBox with a lot of books (their value is an item id)
How do I take this working code:
var t = from ListItem n in lbBooks.Items
where _books.Contains(int.Parse(n.Value))
select n;
foreach(ListItem i in t)
{
i.Selected = true;
}
and convert it to lambda:
lbBooks.Items.Cast<ListItem>()
.Where(n => _books.Contains(int.Parse(n.Value)))
.Select(n => n.Selected = true);
The best option? Don't. LINQ queries are supposed to be just that – queries. And queries aren't supposed to have side effects. Your approach using foreach is perfectly fine.
If you really wanted, you could create your own extension method ForEach(), similar to the one on List<T>, but I don't think that's a good idea.
Your not far off, you need to return the whole object and set Selected to true. Something like:
lbBooks.Items.Cast<ListItem>()
.Where(n => _books.Contains(int.Parse(n.Value)))
.Select(n => SetSelected(n));
The above .Select can be shortend to .Select(SetSelected); if you prefer
private ListItem SetSelected(ListItem listItem)
{
listItem.Selected = true;
return listItem
}
Additionally to save casting you could utilise the SetSelected to handle your casting once you have just the records you want. Your query would then become:
lbBooks.Items.Where(n => _books.Contains(int.Parse(n.Value)))
.Select(n => SetSelected(n));
private ListItem SetSelected(Item item)
{
ListItem result = item as ListItem;
result.Selected = true;
return result;
}
There is no build in ForEach extension method. You can create your own, but I do not see any problem with the code you have.
Cast to .ToList() and use the `ForEach' operator as so:
lbBooks.Items.Cast<ListItem>()
.Where(n => _books.Contains(int.Parse(n.Value)))
.Select(n => n).ToList().ForEach(n=> n.Selected=true);
Related
I am new to C# language, I have started learning LINQ in that
So I just want to convert the code using linq. Is there any way to do. The current implementation is not a stylish one.
var list = new List<int>();
for (int index = 0; index < contentList.Count; index++)
{
list.Add(MyClass.GetCorrespondence(module, index));
}
return list;
You could write it like this:
var list = contentList.Select((_, i) => MyClass.GetCorrespondence(module, i)).ToList();
or like this
var list = Enumerable.Range(0,contentList.Count).Select(i => MyClass.GetCorrespondence(module, i)).ToList();
But, honestly, dont do either! Your code is perfectly readable as it is.
If you must use LINQ for this then you can use the overload for Select which "projects each element of a sequence into a new form by incorporating the element's index." e.g:
list.AddRange(contentList.Select((c, index) => MyClass.GetCorrespondence(c, index));
https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.select?view=netframework-4.8
this method work:
var result= contentList.Select((paramter,index)=>MyClass.GetCorrespondence(module,index)).ToList();
If you're desperate to do it with Linq then you could try:
list.AddRange(Enumerable.Range(0, contentList.Count).Select(index => MyClass.GetCorrespondence(module, index)))
or:
list = Enumerable.Range(0, contentList.Count).Select(index => MyClass.GetCorrespondence(module, index)).ToList();
You could also use the ForEach LINQ statement.
contentList.ForEach(x => list.Add(MyClass.GetCorrespondence(module, x)));
EDIT: Any reason why this was down voted?
I'm getting following string as result while returning a list of string using lambda expression:
System.Linq.Enumerable+WhereSelectEnumerableIterator`2[HOrg.ServiceCatalog.Contracts.Models.IOfferProperty,System.String]
My code is:
IList<string> offerIds = new List<string>();
foreach (var offer in offerProperties)
{
offerIds.Add(offer
.Where(x => x.PropertyDefinitionId == propertyDefinitionId)
.Select(x => x.OfferId)
.ToString());
}
Within foreach loop, offer variable contains expected values. But when I make condition using lambda expression, it returns System.Linq.Enumerable+WhereSelectEnumerableIterator`2 as a result.
When I search for this, I got a few suggestions like,
Copying results of lambda expressions in to a seperate list
Use ToList() for lambda expression then assign it to a result variable
and more suggestion. But no answer is helpful for me.
Is anybody know what's wrong in this code?
Instead of converting sequence to String:
// How can .Net convert sequence into string? The only way is to return type name
// which is unreadable System.Linq.Enumerable+WhereSelectEn...
offer
.Where(x => x.PropertyDefinitionId == propertyDefinitionId)
.Select(x => x.OfferId)
.ToString()
Join the items into a string
// Join items into string with "; " delimiter, e.g. "1; 2; 3; 4"
offerIds.Add(string.Join("; ", offer
.Where(x => x.PropertyDefinitionId == propertyDefinitionId)
.Select(x => x.OfferId)));
If you expect a single result for every offer, try:
IList<string> offerIds = new List<string>();
foreach (var offer in offerProperties)
{
offerIds.Add(offer.Where(x => x.PropertyDefinitionId == propertyDefinitionId).Select(x => x.OfferId).FirstOrDefault()?.ToString());
}
It seems to me that you want a collection of offerIds as a string, where multiple are attached to the offerproperties.
If so, then you are looking for the addrange function. Also move your ToString() call inside the select statement, not after it.
IList<string> offerIds = new List<string>();
foreach (var offer in offerProperties)
{
offerIds.AddRange(offer.Where(x => x.PropertyDefinitionId == propertyDefinitionId).Select(x => x.OfferId.ToString()));
}
Now for each offer, a selection of OfferId-strings is added to your offerIds IList
I have a problem I need to solve efficiently.
I require the index of an element in an IEnumerable source, one way I could do this is with the following
var items = source.Cast<ObjectType>().Where(obj => obj.Start == forDate);
This would give me an IEnumerable of all the items that match the predicate.
if(items != null && items.Any()){
// I now need the ordinal from the original list
return source.IndexOf(items[0]);
}
However, the list could be vast and the operation will be carried out many times. I believe this is inefficient and there must be a better way to do this.
I would be grateful if anyone can point me in the correct direction.
Sometimes, it's good to forget about Linq and go back to basics:
int index = 0;
foeach (ObjectType element in source)
{
if (element.Start == forDate)
{
return index;
}
index++;
}
// No element found
Using Linq, you can take the index of each object before filtering them:
source
.Cast<ObjectType>()
.Select((obj, i) => new { Obj = obj, I = i })
.Where(x => x.Obj.Start == forDate)
.Select(x => x.I)
.FirstOrDefault();
However, this is not really efficient, the following will do the same without allocations:
int i = 0;
foreach (ObjectType obj in source)
{
if (obj.Start == forDate)
{
return i;
}
i++;
}
Your second code sample was invalid: since items is an IEnumerable, you cannot call items[0]. You can use First(). Anyway:
var items = source.Cast<ObjectType>()
.Select((item, index) => new KeyValuePair<int, ObjectType>(index, item))
.Where(obj => obj.Value.Start == forDate);
and then:
if (items != null && items.Any()) {
return items.First().Key;
}
If you need to do this multiple times I would create a lookup for the indices.
ILookup<DateTime, int> lookup =
source
.Cast<ObjectType>()
.Select((e, i) => new { e, i })
.ToLookup(x => x.e.Start, x => x.i);
Now given a forDate you can do this:
IEnumerable<int> indices = lookup[forDate];
Since the lookup is basically like a dictionary that returns multiple values you get the results instantly. So repeating this for multiple values is super fast.
And since this returns IEnumerable<int> you know when there are duplicate values within the source list. If you only need the first one then just do a .First().
At the moment I have to break down this simple operation in two parts, I am sure the would be a better way is hiding from me :
List<int> selectedValues= new List<int>();
...
IEnumerable<RadComboBoxItem> checkedItems = from checkedItem in cblMagistrateCourts.Items.ToList()
where checkedItem.Checked == true
select checkedItem;
foreach (RadComboBoxItem item in checkedItems)
{
if (item.Checked)
selectedValues.Add(Convert.ToInt32(item.Value));
}
I am wanting this to be done server-side only.
How about this?
List<int> selectedValues = cblMagistrateCourts.Items.Where(i => i.Checked)
.Select(i => Convert.ToInt32(i.Value))
.ToList();
Convert the value at same time you're selecting the checkedItem...
List<int> selectedValues = (from checkedItem in cblMagistrateCourts.Items.ToList()
where checkedItem.Checked == true
select Convert.ToInt32(checkedItem.Value)).ToList();
rcb.CheckedItems.Select(x => x.Value).ToList();
How do you loop through IQueryable and remove some elements I don't need.
I am looking for something like this
var items = MyDataContext.Items.Where(x => x.Container.ID == myContainerId);
foreach(Item item in items)
{
if(IsNotWhatINeed(item))
items.Remove(item);
}
Is it possible? Thanks in advance
You should be able to query that further as in this
var filtered = items.Where(itm => IsWhatINeed(itm));
Also notice the subtle change in the boolean function to an affirmative rather than a negative. That (the negative) is what the not operator is for.
items = items.Where( x => !IsNotWhatINeed(x) );
var items = MyDataContext.Items.Where(x => x.Container.ID == myContainerId
&& !IsNotWhatINeed(x));
or
var items = MyDataContext.Items.Where(x => x.Container.ID == myContainerId)
.Where(x=> !IsNotWhatINeed(x));
The other answers are correct in that you can further refine the query with a 'where' statement. However, I'm assuming your query is a Linq2Sql query. So you need to make sure you have the data in memory before further filtering with a custom function:
var items = MyDataContext.Items.Where(x => x.Container.ID == myContainerId)
.ToList(); // fetch the data in memory
var itemsToRemove = items.Where(IsNotWhatINeed);
If you really want to extend the IQueryable, then the 'IsNotWhatINeed' function must be translated to something that Linq2Sql understands.
Try This:
var items = YourDataContext.Items.Where(x => x.Container.ID == myContainerId
&& !IsNotWhatYouNeed(x));