Lambda Statements in Linq - c#

Is it possible to do something like the following in Linq?
List<Group> groupsCollection = new List<Group>();
groups.Select( g => {
String id = g.Attributes["id"].Value;
String title = g.Attributes["title"].Value;
groupsCollection.Add( new Group(id, title) );
} );
This is just an example. I know a Foreach loop would be sufficient but I was querying whether it would be possible or not.
I tried it, and it's saying:
Cannot convert lambda expression to type System.Collections.IEnumerable<CsQuery.IDomObject> because it's not a delegate type
Edit: Group is my custom class. Groups are a collection of CsQuery Dom Objects. You can think of them as a collection of html anchor elements. They are IEnumerable.

I think you're looking for this:
groupsCollection = groups.Select(g =>
new Group(g.Attributes["id"].Value,
g.Attributes["title"].Value)).ToList();
Explanation:
Select() projects each element of a sequence into a new form. (From MSDN)
It's basically a transformation function that takes one IEnumerable and transforms it, in whatever way you like, to another IEnumerable, which seems to be exactly what you want here.

Select() takes a lambda expression that returns a value; it shouldn't have any sife effects.
You want
var groupsCollection = groups.Select(g => {
return ...;
}).ToList();

You can use the constructor to initialize it with the query:
var query = groups.Select( g => {
String id = g.Attributes["id"].Value;
String title = g.Attributes["title"].Value;
return new Group(id, title);
});
List<Group> groupsCollection = new List<Group>(query);
Do not modify colections in a linq-query, instead select data that can be used to modify collections.

As you said, you know using ForEach would be relevant. However you are just curious if you can do it another way. As others pointed out, you can use Select but the code in the {...} should return some value. However, you can do it this way which is better if you want to stop or break the loop depending on some condition using TakeWhile:
groups.TakeWhile( g => {
String id = g.Attributes["id"].Value;
String title = g.Attributes["title"].Value;
groupsCollection.Add( new Group(id, title) );
return true;//If you want to break the loop, just return false accordingly.
});

Related

Access one column from a list to use in another query

I am trying to grab a single column from my linq query and put it into another list may not be the right way of doing it so please excuse me if my code is not
good. Wanting to learn more about linq.
List<StockM> _stockm = new List<StockM>();
List<priceLists> _priceList = new List<priceLists>();
stockm = _db.getStockBySupplierCode(_supplierCode);
foreach (var stockitem in _stockm)
{
_priceList = _db.getPriceTypesByProductCode(stockitem.product, "LPS");
stockitem.lpePrice = Convert.ToDecimal(_priceList.Select(s => s.lpsPrice));
}
I think the probelems lies in how I am attempting to select the column out here
_priceList.Select(s => s.lpsPrice)
try using FirstorDefault() as your _priceList is a list and you are assigning it to a value
_priceList.Select(s => s.lpsPrice).FirstOrDefault();
Also, do you need a where to find a particular value that matches? Just curious
There is several things wrong in your code.
First of all, I encourage you to read the .NET convention. There is no leading _ in local variable, the properties must start with an upper case, for examples.
Then, you do not need to instantiate a default instance if you are going to assign another instance to your variable next. You can assign it directly:
List<StockM> _stockm = _db.getStockBySupplierCode(_supplierCode);
Finally, the Select extension method you are using is already doing a foreach:
var result = _priceList.Select(s => s.lpsPrice);
Is basically (not exactly but it is a start to explain it like this) the same as:
var result = new List<decimal>();
foreach(var priceList in _priceList)
{
result.Add(priceList.lpsPrice);
}
That being said, you can improve your code like this:
List<StockM> stockm = _db.getStockBySupplierCode(_supplierCode);
foreach (var stockitem in stockm)
{
List<priceLists> _priceList = _db.getPriceTypesByProductCode(stockitem.product, "LPS");
stockitem.lpePrice = ??? // you cannot use the Select here as it returns a collection of item. What do you really want to achieve?
}

using lambda, how to apply an existing function to all elements of a list?

Excuse me, a quick question:
I have a list of strings, string are full paths of some files. I would like to get only the filename without the path neither the extension for each string (and to understand lambda more)
Based on the lambda expression in How to bind a List to a DataGridView control? I am trying something like the below:
FilesName = Directory.GetFiles(fbd.SelectedPath).ToList(); // full path
List<string> FilesNameWithoutPath = AllVideosFileNames.ForEach(x => Path.GetFileNameWithoutExtension(x)); // I want only the filename
AllVideosGrid.DataSource = FilesNameWithoutPath.ConvertAll(x => new { Value = x }); // to then bind it with the grid
The error is:
Can not convert void() to List of string
So I want to apply Path.GetFileNameWithoutExtension() for each string in FilesName. And would appreciate any extra description on how Lamba works in this case.
ForEach will execute some code on each item in your list, but will not return anything (see: List<T>.ForEach Method). What you want to do is Select the result of the method (see: Enumerable.Select<TSource, TResult> Method), which would look something like:
List<string> FilesNameWithoutPath = AllVideosFileNames
.Select(x => Path.GetFileNameWithoutExtension(x))
.ToList();
You are using List<T>.ForEach method which takes each element in the list and applies the given function to them, but it doesn't return anything. So what you are doing basically is getting each file name and throwing them away.
What you need is a Select instead of ForEach:
var fileNamesWithoutPath = AllVideosFileNames
.Select(x => Path.GetFileNameWithoutExtension(x))
.ToList();
AllVideosGrid.DataSource = fileNamesWithoutPath;
This will project each item, apply Path.GetFileNameWithoutExtension to them and return the result, then you put that result into a list by ToList.
Note that you can also shorten the Select using a method group without declaring a lambda variable:
.Select(Path.GetFileNameWithoutExtension)

Check if list contains element that contains a string and get that element

While searching for an answer to this question, I've run into similar ones utilizing LINQ but I haven't been able to fully understand them (and thus, implement them), as I'm not familiarized with it. What I would like to, basically, is this:
Check if any element of a list contains a specific string.
If it does, get that element.
I honestly don't know how I would go about doing that. What I can come up with is this (not working, of course):
if (myList.Contains(myString))
string element = myList.ElementAt(myList.IndexOf(myString));
I know WHY it does not work:
myList.Contains() does not return true, since it will check for if a whole element of the list matches the string I specified.
myList.IndexOf() will not find an occurrence, since, as it is the case again, it will check for an element matching the string.
Still, I have no clue how to solve this problem, but I figure I'll have to use LINQ as suggested in similar questions to mine. That being said, if that's the case here, I'd like for the answerer to explain to me the use of LINQ in their example (as I said, I haven't bothered with it in my time with C#). Thank you in advance guys (and gals?).
EDIT: I have come up with a solution; just loop through the list, check if current element contains the string and then set a string equal to the current element. I'm wondering, though, is there a more efficient way than this?
string myString = "bla";
string element = "";
for (int i = 0; i < myList.Count; i++)
{
if (myList[i].Contains(myString))
element = myList[i];
}
You should be able to use Linq here:
var matchingvalues = myList
.Where(stringToCheck => stringToCheck.Contains(myString));
If you simply wish to return the first matching item:
var match = myList
.FirstOrDefault(stringToCheck => stringToCheck.Contains(myString));
if(match != null)
//Do stuff
The basic answer is: you need to iterate through loop and check any element contains the specified string.
So, let's say the code is:
foreach(string item in myList)
{
if(item.Contains(myString))
return item;
}
The equivalent, but terse, code is:
mylist.Where(x => x.Contains(myString)).FirstOrDefault();
Here, x is a parameter that acts like "item" in the above code.
string result = myList.FirstOrDefault(x => x == myString)
if(result != null)
{
//found
}
for (int i = 0; i < myList.Length; i++)
{
if (myList[i].Contains(myString)) // (you use the word "contains". either equals or indexof might be appropriate)
{
return i;
}
}
Old fashion loops are almost always the fastest.
If you want a list of strings containing your string:
var newList = myList.Where(x => x.Contains(myString)).ToList();
Another option is to use Linq FirstOrDefault
var element = myList.Where(x => x.Contains(myString)).FirstOrDefault();
Keep in mind that Contains method is case sensitive.
You could use Linq's FirstOrDefault extension method:
string element = myList.FirstOrDefault(s => s.Contains(myString));
This will return the fist element that contains the substring myString, or null if no such element is found.
If all you need is the index, use the List<T> class's FindIndex method:
int index = myList.FindIndex(s => s.Contains(myString));
This will return the the index of fist element that contains the substring myString, or -1 if no such element is found.
Many good answers here, but I use a simple one using Exists, as below:
foreach (var setting in FullList)
{
if(cleanList.Exists(x => x.ProcedureName == setting.ProcedureName))
setting.IsActive = true; // do you business logic here
else
setting.IsActive = false;
updateList.Add(setting);
}
You should be able to use something like this, it has worked okay for me:
var valuesToMatch = yourList.Where(stringCheck => stringCheck.Contains(myString));
or something like this, if you need to look where it doesn't match.
var valuesToMatch = yourList.Where(stringCheck => !stringCheck.Contains(myString));
you can use
var match=myList.Where(item=>item.Contains("Required String"));
foreach(var i in match)
{
//do something with the matched items
}
LINQ provides you with capabilities to "query" any collection of data. You can use syntax like a database query (select, where, etc) on a collection (here the collection (list) of strings).
so you are doing like "get me items from the list Where it satisfies a given condition"
inside the Where you are using a "lambda expression"
to tell briefly lambda expression is something like (input parameter => return value)
so for a parameter "item", it returns "item.Contains("required string")" . So it returns true if the item contains the string and thereby it gets selected from the list since it satisfied the condition.
To keep it simple use this;
foreach(string item in myList)//Iterate through each item.
{
if(item.Contains("Search Term")//True if the item contains search pattern.
{
return item;//Return the matched item.
}
}
Alternatively,to do this with for loop,use this;
for (int iterator = 0; iterator < myList.Count; iterator++)
{
if (myList[iterator].Contains("String Pattern"))
{
return myList[iterator];
}
}
It is possible to combine Any, Where, First and FirstOrDefault; or just place the predicate in any of those methods depending on what is needed.
You should probably avoid using First unless you want to have an exception thrown when no match is found. FirstOrDefault is usually the better option as long as you know it will return the type's default if no match is found (string's default is null, int is 0, bool is false, etc).
using System.Collections.Generic;
using System.Linq;
bool exists;
string firstMatch;
IEnumerable<string> matchingList;
var myList = new List<string>() { "foo", "bar", "foobar" };
exists = myList.Any(x => x.Contains("o"));
// exists => true
firstMatch = myList.FirstOrDefault(x => x.Contains("o"));
firstMatch = myList.First(x => x.Contains("o"));
// firstMatch => "foo"
firstMatch = myList.First(x => x.Contains("dark side"));
// throws exception because no element contains "dark side"
firstMatch = myList.FirstOrDefault(x => x.Contains("dark side"));
// firstMatch => null
matchingList = myList.Where(x => x.Contains("o"));
// matchingList => { "foo", "foobar" }
Test this code # https://rextester.com/TXDL57489
I have not seen bool option in other answers so I hope below code will help someone.
Just use Any()
string myString = "test";
bool exists = myList
.Where(w => w.COLUMN_TO_CHECK.Contains(myString)).Any();
You can check the list is empty or not in multiple ways.
1)Check list is null and then check count is greater than zero like below:-
if(myList!=null && myList.Count>0)
{
//List has more than one record.
}
2)Check list null and count greater than zero using linq query like below:-
if(myList!=null && myList.Count>0)
{
//List has more than one record.
}

How to store value from a IQueryable list to a string variable?

Hi my code is as below:
List<COSIS_DAL.PaymentsHeader> pheadr = c.GetPaymentHeaderByPayDate(PayDate);
public List<PaymentsHeader> GetPaymentHeaderByPayDate(DateTime payDate)
{
CosisEntities db = new CosisEntities();
IQueryable<PaymentsHeader> query = (from p in db.PaymentsHeaders
where p.PaymentDate.Value.Day == payDate.Day
&& p.PaymentDate.Value.Month == payDate.Month
&& p.PaymentDate.Value.Year == payDate.Year
select p);
return query.ToList();
}
so I want to save the data from pheadr to a string like this:
string keyword = Convert.ToString(pheadr.Select(m => m.VoucherNumber));
but I am not getting the value inside the list. Instead of the value I am getting this:
System.Linq.Enumerable+WhereSelectListIterator`2[COSIS_DAL.PaymentsHeader,System.String]
Please help me on this. I am really in trouble for this. Thanks in advance.
The problem is that pheadr.Select(m => m.VoucherNumber) isn't a single value... It's a collection of values... You could try:
string keyword = string.Join(", ", pheadr.Select(m => Convert.ToString(m.VoucherNumber)));
if you really want multiple voucher numbers separated by a ,.
or you could put it in a separate collection:
List<string> vouchers = pheadr.Select(m => Convert.ToString(m.VoucherNumber)).ToList();
Maybe something like this:
var keywords = pheadr.Select(x=>x.VoucherNumber.ToString()).ToList();
It will select all voucher numbers to list of strings. Is it what you wanted? keywords is List<string>
The string you are getting is because you are converting Linq expression to string, not inner field.
For only first record, use:
var keyword = Convert.ToString(pheadr.First().VoucherNumber);
If you are not sure that it will always return one value try:
var ph = pheadr.FirstOrDefault();
var keyword = ph!=null?Convert.ToString(ph.VoucherNumber):"";
EDIT:
as #xanatos suggested I used Convert instead ToString
Since pheadr is a collection of PaymentsHeader objects, the line
pheadr.Select(m => m.VoucherNumber)
will select each PaymentsHeader VoucherNumber property, which I'll assume is a string. So, the thing that will be returned will be a collection of strings. You can loop through it, you can cast it to a list or an array, or you can stick it in a stew, but you can't just call .ToString on it. That invokes the default object.ToString behaviour that just dumps the name of the class, which is what you got.
If you want to extract, for example, a comma-separated list of those strings, you can use:
string.Join(",", pheadr.Select(m => m.VoucherNumber))
try this
string keyword ;
if(pheader != null)
keyword = pheader.FirstOrDefault().VoucherNumber;
else
keyword = "";

Find any entities that contain any one string from a list

I can't quite get my head around this one for some reason.
Say we have a class Foo
public class Foo
{
public string Name {get;set;}
}
And we have a generic list of them. I want to search through the generic list and pick out those that have a Name that contains any from a list of strings.
So something like
var source = GetListOfFoos();//assume a collection of Foo objects
var keywords = GetListOfKeyWords();//assume list/array of strings
var temp = new List<Foo>();
foreach(var keyword in keywords)
{
temp.AddRange(source.Where(x => x.Name.Contains(keyword));
}
This issue here being a) the loop (doesn't feel optimal to me) and b) each object might appear more than once (if the name was 'Rob StackOverflow' and there was a keyword 'Rob' and keyword 'Stackoverflow').
I guess I could call Distinct() but again, it just doesn't feel optimal.
I think I'm approaching this incorrectly - what am I doing wrong?
I want to search through the generic list and pick out those that have
a Name that contains any from a list of strings.
Sounds rather easy:
var query = source.Where(e => keywords.Any(k => e.Name.Contains(k)));
Add ToList() to get results as a List<Foo>:
var temp = query.ToList();
Put the keywords into a HashSet for fast lookup, so that you're not doing a N2 loop.
HashSet<string> keywords = new HashSet<string>(GetListOfKeyWords(), StringComparer.InvariantCultureIgnoreCase);
var query = source.Where(x => keywords.Contains(x.Name));
EDIT: Actually, I re-read the question, and was wrong. This will only match the entire keyword, not see if the Name contains the keyword. Working on a better fix.
I like MarcinJuraszek's answer, but I would also assume you want case-insensitive matching of the keywords, so I'd try something like this:
var query = source.Where(f => keywords.Any(k => f.Name.IndexOf(k, StringComparison.OrdinalIgnoreCase) >= 0));

Categories