I'm trying to write a simple Lambda expression in C#:
int numElements = 3;
string[]firstnames = {"Dave", "Jim", "Rob"};
string[]lastnames = {"Davidson", "Jameson", "Robertson"};
List<Person> people = new List<Person>();
for(int i = 0 ; i < numElements; i++)
{
people.Add(new Person { FirstName = firstnames[i], LastName = lastnames[i] });
}
bool test = people.Contains(p => p.FirstName == "Bob");
My understanding of Lambda expressions and how they work is still a little shady and I miffed as to why this will not work...I'm trying to find out if a list contains a name...
Are you looking for:
bool test = people.Any(p => p.FirstName == "Bob");
Or are you mixing Rob and Bob?
The problem here is not lambdas but instead the boundaries of the for loop. The arrays you defined have a length of 3 but numElements is defined to have a value of 10. This means you will get an exception for an illegal array index on the 4th iteration of the loop. Try the following
int numElements = 3;
Or more simply remove the numElements variable and instead iterate to the length of the firstnames array
for (int i = 0; i < firstnames.length; i++) {
...
}
EDIT
OP indicated that the numElements originally posted was a typo. Other possible sources of error in the code
Use "Rob" instead of "Bob" if you want to find a matching element
The Contains method on GenericList<T> needs to have a compatible delegate signature. Func<T, bool> for example
Make sure you are linking the System.Linq namemespace, i.e.
using System.Linq;
You are using the Contains method. This method expects a Person and will use an equality comparison to determine if your collection already contains it. In the default case, the equality comparison defaults to reference comparison so it will never contain it, but that's another topic.
To achieve your goal, use the Any method. This will tell you if ANY of the elements in your collection conform to a condition.
people.Any(p => p.FirstName == "BoB");
You may want to read about the extension methods First and FirstOrDefault and Where as they would also solve your problem.
You don't set numElements to the correct value ( you set it to 10, but your arrays only have 3 values) - furthermore you don't even need it, just use a collection initializer instead of those separate string arrays:
GenericList<Person> people = new GenericList<Person>()
{
new Person { FirstName = "Dave", LastName = "Davidson" },
new Person { FirstName = "Jim", LastName = "Jameson" }
new Person { FirstName = "Rob", LastName = "Robertson" }
}
Now assuming your GenericList<T> class implements IEnumerable<T> you can use Any() to do your test:
bool test = people.Any(p => p.FirstName == "Bob");
what your real problem with this lambdas ?
If because you have test false then that's true you don't have "Bob" in firstName
bool test = people.Contains(p => p.FirstName == "Bob");
and
string[]firstnames = {"Dave", "Jim", "Rob"};
Couple of problems here.
One: GenericList is not a type. You were probably looking for the generic type System.Collections.Generic.List<T>.
Two: Contains accepts a Person in your example, not a delegate (lambdas are a new way to write delegates as of C# 3). One way to get what you want here would be to combine Where and Count, in the form of bool test = people.Where(p => p.FirstName == "Bob").Count() > 0;
// We will use these things:
Predicate<Person> yourPredicate = p => p.FirstName == "Bob";
Func<Person, bool> yourPredicateFunction = p => p.FirstName == "Bob";
Person specificPerson = people[0];
// Checking existence of someone:
bool test = people.Contains(specificPerson);
bool anyBobExistsHere = people.Exists(yourPredicate);
// Accessing to a person/people:
IEnumerable<Person> allBobs = people.Where(yourPredicateFunction);
Person firstBob = people.Find(yourPredicate);
Person lastBob = people.FindLast(yourPredicate);
// Finding index of a person
int indexOfFirstBob = people.FindIndex(yourPredicate);
int indexOfLastBob = people.FindLastIndex(yourPredicate);
You should play with LINQ methods somewhile...
Related
I put the following code segment in .NET Fiddle but it printed out System.Linq.Enumerable+WhereArrayIterator1[System.String] I'd like to print out each content in result, in order to understand how Select works. Can someone please help to point out what the problem is? Many thanks!
string[] sequ1 = { "abcde", "fghi", "jkl", "mnop", "qrs" };
string[] sequ2 = { "abc", "defgh", "ijklm", "nop" };
var result =sequ1.Select( n1 => sequ2.Where(n2 => n1.Length < n2.Length) );
foreach( var y in result)
{
Console.WriteLine(y);
}
You are actually returning a collection of collections.
sequ1.Select( n1 => sequ2.Where(n2 => n1.Length < n2.Length) );
For each element in sequ1, this statement filters sequ2 to find all of the elements from the second sequence where the current value in the first sequence is shorter than it and then maps to a new collection containing each of those results.
To describe what Select is actually doing:
You start with a collection of things. In your case: sequ1 which has type IEnumerable<string>
You supply it with a function, this function takes an argument of the type of thing you supplied it with a collection of and has a return type of some other thing, in your case:
fun n1 => sequ2.Where(n2 => n1.Length < n2.Length)
Your function takes a string and returns an IEnumerable<string>
Finally, it returns a result containing a collection of each element in the original collection transformed to some new element by the function you supplied it with.
So you started with IEnumerable<string> and ended up with IEnumerable<IEnumerable<string>>.
That means you have a collection for each value that appears in sequ1.
As such, you would expect the result to be:
{{}, {"defgh", "ijklm"}, {"defgh", "ijklm"}, {"defgh", "ijklm"}, {"defgh", "ijklm"}}
You can inspect the results by adding another loop.
foreach(var y in result)
{
foreach(var z in result)
{
Console.WriteLine(z);
}
}
Change your Select to SelectMany:
var result = sequ1.SelectMany(n1 => sequ2.Where(n2 => n1.Length < n2.Length));
I may be wrong, but I think the OP wants to compare both arrays, and for each element, print the longest one.
If that's the case, I would do it as follows:
var result = sequ1.Take(sequ2.Length)
.Select((n1, i) =>
(n1.Length > sequ2.ElementAt(i).Length)
? n1
: sequ2.ElementAt(i));
Explanation:
Use Take to only go as long as the length of the second array, and avoid nullreference exceptions later on.
Use Select, with two arguments, the first is the string, the second is the index.
Use ElementAt to find the corresponding element in sequ2
I don't know about this example is about to help you to understand how select work. A more simple exmaple what i think is this.
public class Person {
public string Name { get; set; }
public string LastName { get; set; }
}
public class Test {
public Test() {
List<Person> persons = new List<Person>();
persons.Add(new Person() { Name = "Person1",LastName = "LastName1" });
persons.Add(new Person() { Name = "Person2",LastName = "LastName2" });
var getNamesFromPersons = persons.Select(p => p.Name);
}
}
If you are beginning c#, you need to sideline the keyword "var" from your code.
Force yourself to write out what the variables really are:
If you forego the use of var, you would have seen why your code was Console.Writing what it did.
string[] sequ1 = { "abcde", "fghi", "jkl", "mnop", "qrs", };
string[] sequ2 = { "abc", "defgh", "ijklm", "nop", };
IEnumerable<IEnumerable<string>> result = sequ1.Select(n1 => sequ2.Where(n2 => n1.Length < n2.Length));
foreach (IEnumerable<string> y in result)
{
foreach (string z in y)
{
Console.WriteLine(z);
}
}
Why the code below returns nothing when I try to query an IList type object?
IList<Person> personRecord = new List<Person>
{
new Person{ Name = "Samuel"},
new Person{ Name = "Kenny Sammy"},
new Person{ Name = "Jame Sam Lee"}
};
var names = from b in personRecord
where personRecord.Any(d => d.Name == "Sam")
select b;
return names.ToList();
Don't use Any simply use the condition in Where clause like:
var names = from b in personRecord
where b.Name == "Sam"
select b;
or with a method syntax:
var names = personRecod.Where(b=> b.Name == "Sam");
If you are looking to match partial contents then use Contains like:
var names = personRecod.Where(b=> b.Name.Contains("Sam"));
To compare partial content with ignoring case use IndexOf like:
var names = personRecod.Where(b=> b.Name.IndexOf("Same", StringComparison.InvariantCultureIgnoreCase) > -1);
.Any returns a boolean, true/false, for whether any item in that collection satisfies your condition. If you changed your var names to the type you expected to receive (string) then you'd receive an error highlighting this.
As has been stated, what you are looking for is just the .Where method, or possibly a .FirstOrDefault or .First.
If you are just looking for the third item (as it's the only one having a name containing the complete word 'Sam') then:
var names = personRecord
.Where(p => p.Name.Split(new char[] {' '}).Contains("Sam"));
I have list of type Person which has 3 properties Id, Name, Age
var per1 = new Person((1, "John", 33);
var per2 = new Person((2, "Anna", 23);
var persons = new List<Person>();
persons.Add(per1);
persons.Add(per2);
using linq I want to select person which age matched with my input, for example 33.
I know how to use any but I dont know how to select object which matches with my condition.
For one match:
var match = persons.Single(p => your condition);
For many matches, use persons.Where(condition). There are also many variants of picking just one person, such as FirstOrDefault, First, Last, LastOrDefault, and SingleOrDefault. Each has slightly different semantics depending on what exactly you want.
You can use Enumerable.Where and it will return all the matching elements collection.
var res = persons.Where(c=>c.AttributeName == 23);
If you want to ensure you have only match you can use single.
var res = persons.Single(c=>c.AttributeName == 23);
Single Returns the only element of a sequence, and throws an exception if there is not exactly one element in the sequence.
It is very simple.
var per1 = new Person(1, "John", 33);
var per2 = new Person(2, "Anna", 23);
var persons = new List<Person>();
persons.Add(per1);
persons.Add(per2);
var sirec = persons.Select(x => x.age = 33);
Try this and let me know
Note: If it is single value use "Single" instead of "Select"
Please have a look at this.
if (model.Any(i => i.ParamKey == Key))
return model.Where(i => i.ParamKey == Key).First().ParamValue;
or
if (model.Any(i => i.ParamKey == Key))
return model.Where(i => i.ParamKey == Key).First();
I know there are a lot of examples of this on the web, but I can't seem to get this to work.
Let me try to set this up, I have a list of custom objects that I need to have limited on a range of values.
I have a sort variable that changes based on some action on the UI, and I need to process the object differently based on that.
Here is my object:
MyObject.ID - Just an identifier
MyObject.Cost - The cost of the object.
MyObject.Name - The name of the object.
Now I need to filter this based on a range in the cost, so I will have something similar to this, considering that I could be limiting by Either of my bottom two properties.
var product = from mo in myobject
where mo.Cost <= 10000
or
var product = from mo in myobject
where mo.Name equals strName
Now I have the dynamic linq in my project, but I'm not figuring out how to get it to actually work, as when I do some of the examples I am only getting:
Func<Tsourse>bool> predicate
as an option.
Update:
I am trying to find a solution that helps me Objectify my code, as right now it is a lot of copy and paste for my linq queries.
Update 2:
Is there an obvious performance difference between:
var product = from mo in myobject
... a few joins ...
where mo.Cost <= 10000
and
var product = (from mo in myobject
... a few joins ...)
.AsQueryable()
.Where("Cost > 1000")
Maybe not directly answering your question, but DynamicQuery is unnecessary here. You can write this query as:
public IEnumerable<MyObject> GetMyObjects(int? maxCost, string name)
{
var query = context.MyObjects;
if (maxCost != null)
{
query = query.Where(mo => mo.Cost <= (int)maxCost);
}
if (!string.IsNullOrEmpty(name))
{
query = query.Where(mo => mo.Name == name);
}
return query;
}
If the conditions are mutually exclusive then just change the second if into an else if.
I use this pattern all the time. What "Dynamic Query" really means is combining pure SQL with Linq; it doesn't really help you that much with generating conditions on the fly.
using System.Linq;
var products = mo.Where(x => x.Name == "xyz");
var products = mo.Where(x => x.Cost <= 1000);
var products = mo.Where(x => x.Name == "xyz" || x.Cost <= 1000);
Read this great post on DLINQ by ScottGu
Dynamic LINQ (Part 1: Using the LINQ Dynamic Query Library)
You would need something like
var product = myobject.Where("Cost <= 10000");
var product = myobject.Where("Name = #0", strName);
If you downloaded the samples you need to find the Dynamic.cs file in the sample. You need to copy this file into your project and then add
using System.Linq.Dynamic; to the class you are trying to use Dynamic Linq in.
EDIT: To answer your edit. Yes, there is of course a performance difference. If you know the variations of filters beforehand then I would suggest writing them out without using DLINQ.
You can create your own Extension Method like so.
public static class FilterExtensions
{
public static IEnumerable<T> AddFilter<T,T1>(this IEnumerable<T> list, Func<T,T1, bool> filter, T1 argument )
{
return list.Where(foo => filter(foo, argument) );
}
}
Then create your filter methods.
public bool FilterById(Foo obj, int id)
{
return obj.id == id;
}
public bool FilterByName(Foo obj, string name)
{
return obj.name == name;
}
Now you can use this on an IEnumerable<Foo> very easily.
List<Foo> foos = new List<Foo>();
foos.Add(new Foo() { id = 1, name = "test" });
foos.Add(new Foo() { id = 1, name = "test1" });
foos.Add(new Foo() { id = 2, name = "test2" });
//Example 1
//get all Foos's by Id == 1
var list1 = foos.AddFilter(FilterById, 1);
//Example 2
//get all Foo's by name == "test1"
var list2 = foos.AddFilter(FilterByName, "test1");
//Example 3
//get all Foo's by Id and Name
var list1 = foos.AddFilter(FilterById, 1).AddFilter(FilterByName, "test1");
Kindly let me know the difference between the "where" in (1) and "where()" in (2).
When to use "where" and "where()" ?
List<Person> pList =
new List<Person>
{
new Person
{EmpNo=1,FirstName="Marc",LastName="Loel",Salary=3434},
new Person
{EmpNo=2, FirstName="Steve",LastName="Kaith",Salary=4545},
new Person
{EmpNo=3,FirstName="Neol",LastName="Henk",Salary=2222},
};
(1) var v = from p in pList where p.EmpNo == 1 select new { p.FirstName };
(2) var query =pList .Where(p => p.EmpNo == 1)
.Select(p => new { p.FirstName});
The difference is that one form is easier to read and the other form is more difficult to read. Trouble is, about half the people think the first one is easier, and half the people think the second one is the easier one! Choose the one you like best and stick with it; they mean exactly the same thing.
There is no real difference. The first where (and select) are a special in-language query expression that get translated by the compiler into those other lambda-based Where and Select methods.
It's just syntactic sugar. In fact, if you just have a class with the correct Where method, even if the class isn't enumerable, you can use the syntactic magic:
class MyClass
{
public IQueryable<int> Where(Func<int, bool> predicate)
{
return Enumerable.Range(1, 100).AsQueryable();
}
}
static void Main(string[] args)
{
var q = from p in new MyClass()
where p == 10
select p;
}
This doesn't do anything, but it builds and will call that method.
I believe they are identical. Microsoft created the syntax in (1) for readability, but the compiler handles it as (2).
There is no difference. Number (1) is just written with some syntactic sugar.
Quick look at the code in reflector and it looks like this:
var v = pList.Where<Person>(delegate (Person p) {
return (p.EmpNo == 1);
}).Select(delegate (Person p) {
return new { FirstName = p.FirstName };
});
var query = pList.Where<Person>(delegate (Person p) {
return (p.EmpNo == 1);
}).Select(delegate (Person p) {
return new { FirstName = p.FirstName };
});
As you can see, they are exactly the same.
The difference (if you want to be picky) is that the first one is LINQ, and the second one isn't.
LINQ is the integrated query language that you see in the first example, and the compiler turns it into using the extension methods seen in the second example.
There are some additional features in.where () method e.g. you can use index extension of where method.
But for given example its just readability.