Could not find an implementation of the query pattern Error - c#

Given
var selectedItems = listBoxControl1.SelectedItems;
var selectedItemsList = (from i in selectedItems
select i).ToList();
I receive Error
Could not find an implementation of the query pattern for source type
'DevExpress.XtraEditors.BaseListBoxControl.SelectedItemCollection'.
'Select' not found. Consider explicitly specifying the type of the
range variable 'i'.
using system.LINQ Done
I can use foreach so it must implement IEnumerable. I prefer to use LINQ over foreach to gather each string, if possible.
I want to take the ToString() values for each SelectedItem in the list box control and stick them in a List<string>. How can I do it?

I can use foreach so it must implement IEnumerable.
That's not actually true, but it's irrelevant here. It does implement IEnumerable, but not IEnumerable<T> which is what LINQ works over.
What's actually in the list? If it's already strings, you could use:
var selectedItemsList = selectedItems.Cast<string>().ToList();
Or if it's "any objects" and you want to call ToString you can use:
var selectedItemsList = selectedItems.Cast<object>()
.Select(x => x.ToString())
.ToList();
Note that the call to Cast is why the error message suggested using an explicitly typed range variable - a query expression starting with from Foo foo in bar will be converted to bar.Cast<Foo>()...

For LINQ to work, you need an IEnumerable<T>, straight IEnumerable isn't enough. Try:
var selectedItems = listboxControl1.SelectedItems.Cast<T> //where T is the actual type of the item

Try just
var result = listBoxControl1.SelectedItems.Cast<MyItemType>().ToList();

Related

C# use LINQ to query custom list and return new subset list

I have a list of a custom type called Holdings. I am trying to query the list based on one property of the Holdings object to return a new list of Holdings. The LINQ query below does work correctly but I would like to replace var unitHld with List unitHld but can't get the code to work.
var unitHld = from hld in _holdingList
where hld.FundCode == lookThroList[i].FundCode
select new Holding() { Currency = hld.Currency,
FundCode = lookThroList[i].FundCode,
IdSedol = hld.IdSedol,
Nominal = hld.Nominal * unitWgt,
Price = hld.Price };
This new list is then slightly altered before being added back to the original list (I know the logic sounds strange but please accept this is how it has to be done). However because unitHld is var the line below does not work.
_holdingList.Add(unitHld);
The following call only adds a single item (where the item must be the same type as the list's elements):
_holdingList.Add(unitHld);
But you want to add a range of items, so do it like this:
_holdingList.AddRange(unitHld);
where unitHld is IEnumerable<T> and T is the type of the list's elements.
(This answer assumes that holdingList is of type List<T>, and that T is in fact Holding for your example.)
See List.AddRange() for details.
C# is statically typed.
var is not a type, all it does is a shortcut for in your case typing IEnumerable<Holding>.
If you want the result to be List<Holding> then all you need to do is wrap your query in brackets and put .ToList() at the end.
However, to append this to another list, you don't need to do that. Simply call .AddRange on the other list.
Alternatively, you can use Concat
var bothLists = aList.Concat(anotherList);
I would like to replace var unitHld with List unitHld but can't get the code to work.
You need to call ToList() on the result of the query:
var unitHld = from hld in _holdingList
where hld.FundCode == lookThroList[i].FundCode
select new Holding() { Currency = hld.Currency,
FundCode = lookThroList[i].FundCode,
IdSedol = hld.IdSedol,
Nominal = hld.Nominal * unitWgt,
Price = hld.Price };
List<Holding> unitHldList = unitHld.ToList();
This new list is then slightly altered before being added back to the original list
Once the data is in unitHldList, you can alter it as needed.
the line below does not work. _holdingList.Add(unitHld);
When you add the content of a collection to a List<T>, use AddRange method instead of Add:
_holdingList.AddRange(unitHldList);
Try this:
_holdingList.AddRange(unitHld);

How to remove x items from collection using LINQ?

Is there a way to remove all items except first one from any type of collection (Control.Items, List ....) using LINQ only ?
No. LINQ is designed for querying collections (no side-effects), not for adding or removing items.
What you can do is write a query that takes the first element of the collection:
var result = source.Take(1);
Note that LINQ doesn't work with all types of collections; you need a LINQ provider to make LINQ work. For instance, source must implement IEnumerable<T> to use the extension methods of the Enumerable Class (LINQ-to-Objects).
How about something using reflection?
static void RemoveButFirst(object o){
Type t = o.GetType();
System.Reflection.MethodInfo rm = t.GetMethod("RemoveAt",
new Type[]{typeof(int)});
System.Reflection.PropertyInfo count = t.GetProperty("Count");
for (int n = (int)(count.GetValue(o,null)) ; n>1; n--)
rm.Invoke(o, new object[]{n-1});
}
This would work any time your collection exposed an int Count property and a RemoveAt(int) method, which I think those collections should.
And a more concise version, using dynamic, if you work with C# 4.0:
public static void RemoveBut(dynamic col, int k){
for (int n = col.Count; n>k; n--)
col.RemoveAt(n-1);
}
You can use .Take(1), but it returns a new collection, and leaves the original intact.
The idea of LINQ came from functional programming where everything is immutable, because of that, they didn't make it possible to modify the collections with LINQ.
Jon Skeet has a comment on the subject: LINQ equivalent of foreach for IEnumerable<T>
How about (in linq):
var result = list.Where(l => l != list.First());
But this would be better:
var result = list.Take(1);
List<string> collection = new List<string>();
collection.RemoveAll(p => p.StartsWith("something"));
listXpto.Where(x=>true /* here goes your query */)
.Select(x=>{listXpto.Remove(x); return null})
But I donĀ“t know the real utility of that.
Remember that the remove method is for ILists, not IQueryable in general.

How to get an empty list of a collection?

I have a collection of anonymous class and I want to return an empty list of it.
What is the best readable expression to use?
I though of the following but I don't think they are readably enough:
var result = MyCollection.Take(0).ToList();
var result = MyCollection.Where(p => false).ToList();
Note: I don't want to empty the collection itself.
Any suggestion!
Whats about:
Enumerable.Empty<T>();
This returns an empty enumerable which is of type T. If you really want a List so you are free to do this:
Enumerable.Empty<T>().ToList<T>();
Actually, if you use a generic extension you don't even have to use any Linq to achieve this, you already have the anonymous type exposed through T
public static IList<T> GetEmptyList<T>(this IEnumerable<T> source)
{
return new List<T>();
}
var emp = MyCollection.GetEmptyList();
Given that your first suggestion works and should perform well - if readability is the only issue, why not create an extension method:
public static IList<T> CreateEmptyCopy(this IEnumerable<T> source)
{
return source.Take(0).ToList();
}
Now you can refactor your example to
var result = MyCollection.CreateEmptyCopy();
For performance reasons, you should stick with the first option you came up with.
The other one would iterate over the entire collection before returning an empty list.
Because the anonymous type there is no way, in source code, to create a list. There is, however, a way to create such list through reflection.

C# - Populate a list using lambda expressions or LINQ

It's been a while since I've used lambda expressions or LINQ and am wondering how I would do the following (I know I can use a foreach loop, this is just out of curiosity) using both methods.
I have an array of string paths (does it make a difference if it's an array or list here?) from which I want to return a new list of just the filenames.
i.e. using a foreach loop it would be:
string[] paths = getPaths();
List<string> listToReturn = new List<string>();
foreach (string path in paths)
{
listToReturn.add(Path.GetFileName(path));
}
return listToReturn;
How would I do the same thing with both lambda and LINQ?
EDIT: In my case, I'm using the returned list as an ItemsSource for a ListBox (WPF) so I'm assuming it's going to need to be a list as opposed to an IEnumerable?
Your main tool would be the .Select() method.
string[] paths = getPaths();
var fileNames = paths.Select(p => Path.GetFileName(p));
does it make a difference if it's an array or list here?
No, an array also implements IEnumerable<T>
Note that this minimal approach involves deferred execution, meaning that fileNames is an IEnumerable<string> and only starts iterating over the source array when you get elements from it.
If you want a List (to be safe), use
string[] paths = getPaths();
var fileNames = paths.Select(p => Path.GetFileName(p)).ToList();
But when there are many files you might want to go the opposite direction (get the results interleaved, faster) by also using a deferred execution source:
var filePaths = Directory.EnumerateFiles(...); // requires Fx4
var fileNames = filePaths.Select(p => Path.GetFileName(p));
It depends on what you want to do next with fileNames.
I think by "LINQ" you really mean "a query expression" but:
// Query expression
var listToReturn = (from path in paths
select Path.GetFileName(path)).ToList();
// Extension methods and a lambda
var listToReturn = paths.Select(path => Path.GetFileName(path))
.ToList();
// Extension methods and a method group conversion
var listToReturn = paths.Select(Path.GetFileName)
.ToList();
Note how the last one works by constructing the projection delegate from a method group, like this:
Func<string, string> projection = Path.GetFileName;
var listToReturn = paths.Select(projection).ToList();
(Just in case that wasn't clear.)
Note that if you don't need to use this as a list - if you just want to iterate over it, in other words - you can drop the ToList() call from each of these approaches.
It's just:
var listToReturn = getPaths().Select(x => Path.GetFileName(x)).ToList();
As already stated in other answers, if you don't actually need a List<string> you can omit the ToList() and simply return IEnumerable<string> (for example if you just need to iterate it, IEnumerable<> is better because avoids the creation of an other list of strings)
Also, given that Select() method takes a delegate, and there's an implicit conversion between method groups and delegates having the same signature, you can skip the lambda and just do:
getPaths().Select(Path.GetFileName)
You could do it like this:
return getPaths().Select(Path.GetFileName);
listToReturn = paths.ToList().Select(p => Path.GetFileName(p));

Most succinct way to convert ListBox.items to a generic list

I am using C# and targeting the .NET Framework 3.5. I'm looking for a small, succinct and efficient piece of code to copy all of the items in a ListBox to a List<String> (Generic List).
At the moment I have something similar to the below code:
List<String> myOtherList = new List<String>();
// Populate our colCriteria with the selected columns.
foreach (String strCol in lbMyListBox.Items)
{
myOtherList.Add(strCol);
}
Which works, of course, but I can't help but get the feeling that there must be a better way of doing this with some of the newer language features. I was thinking of something like the List.ConvertAll method but this only applies to Generic Lists and not ListBox.ObjectCollection collections.
A bit of LINQ should do it:-
var myOtherList = lbMyListBox.Items.Cast<String>().ToList();
Of course you can modify the Type parameter of the Cast to whatever type you have stored in the Items property.
The following will do it (using Linq):
List<string> list = lbMyListBox.Items.OfType<string>().ToList();
The OfType call will ensure that only items in the listbox's items that are strings are used.
Using Cast, if any of the the items are not strings, you will get an exception.
How about this:
List<string> myOtherList = (from l in lbMyListBox.Items.Cast<ListItem>() select l.Value).ToList();
What about:
myOtherList.AddRange(lbMyListBox.Items);
EDIT based on comments and DavidGouge's answer:
myOtherList.AddRange(lbMyListBox.Items.Select(item => ((ListItem)item).Value));
You don't need more. You get List of all values from Listbox
private static List<string> GetAllElements(ListBox chkList)
{
return chkList.Items.Cast<ListItem>().Select(x => x.Value).ToList<string>();
}

Categories

Resources