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();
Related
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 a list of people and I'd like to use LINQ (query syntax) to get an anonymous type containing all the firstnames and all the second names.
If I were to use a foreach:
var firstNames = new HashSet<string>();
var secondNames = new HashSet<string>();
foreach (Person p in ListOfPersons)
{
firstNames.Add(p.firstName);
secondNames.Add(p.secondName);
}
What is an equivalent and efficient LINQ statement that returns an anonymous type? Eg, allNames.FirstNames and allNames.SecondNames.
EDIT: when I say efficient, I mean that it loops over the ListOfPersons once, as in the foreach example above.
EDIT 2: the names should be distinct; I changed the List<> to HashSet<> in the foreach example
If you don't want to iterate ListOfPersons twice the only way I see it in linq is
var firstNames = new List<string>();
var secondNames = new List<string>();
persons.Aggregate(Tuple.Create(firstNames, secondNames), (tuple, person) =>
{
tuple.Item1.Add(person.firstName);
tuple.Item2.Add(person.secondName);
return tuple;
});
but I think foreach is much better.
Try this:
var AnonList = ListOfPersons.Select(x=> new {firstname = x.firstName, secondname = x.secondName});
var nameList = from l in ListOfPersons
select new { FirstName = l.Firstname, Surname = l.Surname};
How about this:
var allNames = new
{
firstNames = new List<string>(),
secondNames = new List<string>()
};
listOfPersons.ForEach( p =>
{
allNames.firstNames.Add( p.firstName );
allNames.secondNames.Add( p.secondName );
} );
Counter intuitively, this is the most efficient:
var names = new
{
firstNames = ListOfPersons.Select(x => x.firstName).Distinct().ToList(),
secondNames = ListOfPersons.Select(x => x.secondName).Distinct().ToList(),
};
It turns out that iterating over the list twice is more efficient that concocting a method to iterate over it once as many more temporary variables are created. I've done speed tests on this kind of thing and iterating over the list multiple times wins.
I'm constructing a linq query that will check is a string in the DB contains any of the strings in a list of strings.
Something like.
query = query.Where(x => x.tags
.Contains(--any of the items in my list of strings--));
I'd also like to know how many of the items in the list were matched.
Any help would be appreciated.
Update: I should have mentioned that tags is a string not a list. And I am adding on a couple more wheres that are not related to tags before the query actually runs. This is running against entity framework.
EDIT: This answer assumed that tags was a collection of strings...
It sounds like you might want:
var list = new List<string> { ... };
var query = query.Where(x => x.tags.Any(tag => list.Contains(tag));
Or:
var list = new List<string> { ... };
var query = query.Where(x => x.tags.Intersect(list).Any());
(If this is using LINQ to SQL or EF, you may find one works but the other doesn't. In just LINQ to Objects, both should work.)
To get the count, you'd need something like:
var result = query.Select(x => new { x, count = x.tags.Count(tag => list.Contains(tag)) })
.Where(pair => pair.count != 0);
Then each element of result is a pair of x (the item) and count (the number of matching tags).
I've done something like this before:
var myList = new List<string>();
myList.Add("One");
myList.Add("Two");
var matches = query.Where(x => myList.Any(y => x.tags.Contains(y)));
like this:
List<string> list = new List<string>();
list.Add("One");
list.Add("Two");
var result = query.Where(x => list.Contains(x.tags));
I am not quite sure from your question if x.tags is a string or list, if it is a list Jon Skeet's answer is correct. If I understand you correctly though x.tags is a string of strings. If so then the solution is:
list.Any(x => x.tags.IndexOf(x) > -1)
to count them do
list.Count(x => x.tags.IndexOf(x) > -1)
var t = new List<string> { "a", "b", "c" };
var y = "a b d";
var res = y.Count(x => t.Contains(x.ToString()));
I faced a similar problem recently and here's how I managed to work it out:
var list = [list of strings];
if (list != null && list.Any())
{
queryable = queryable.Where(x => x.tags != null);
var tagQueries = new List<IQueryable<WhateverTheDbModelIs>>();
foreach (var element in list)
{
tagQueries.Add(queryable.Where(x => x.tags.Contains(element)));
}
IQueryable<WhateverTheDbModelIs> query = tagQueries.FirstOrDefault();
foreach (var tagQuery in tagQueries)
{
query = query.Union(tagQuery);
}
queryable = queryable.Intersect(query);
}
probably not the best option but something a less experienced developer can understand and use
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...
This seems like it would be easy enough
var orx = gg.Where(x=>x.ProductAttributes.Any (pa =>pa.AttributeId == "home"));
returns gg when product attributes has a value of "home"
I need it to return where and gg has product attribute values from an array
i.e.
var orx = gg.Where(x=>x.ProductAttributes.Any (pa =>pa.AttributeId in "home,work"));
what about...
string[] values = new string[] { "home", "work" };
var orx = gg.Where(x => x.ProductAttributes.Any(pa => values.Contains(pa.AttributeId));
or even "home,work".Contains(pa.AttributeId) should work, if your list is as reliable as your example. (I by no mean recommend this unless you can ensure that AttributeId will not be a substring of any of the list words.. such as "me")
Using Enumerable.Contains():
var orx = gg.Where(x => x.ProductAttributes
.Any(pa =>
array.Containspa(pa.AttributeId));
var orx = gg.Where(x => x.ProductAttributes
.Any(pa =>
"home, work".Split(',').Contains(pa.AttributeId));