nested foreach as LINQ with chained linked List - c#

I have a List within a list. I only need the one value from the list and can do obtain my result with a nested foreach but I want to use a LINQ query of some sort.
my code:
var myCity = from c in CountryLists
select (from city in c.stateList
where city.name == passedInValue
select city.name).FirstorDefault();
This returns myCity as a list of some sort with all values as null EXCEPT for where the match was found.
i don't want to have to walk through the city list to find the name. How can I have only one value in myCity; either null or the desired name?

First, use SelectMany to flatten the list, then FirstOrDefault to filter:
CountryList.SelectMany(c => c.stateList).FirstOrDefault(d => d.Name == passedInValue);
Note that because FirstOrDefault can take a predicate, you don't actually need the Where clause.

How about using SelectMany:
var city = CountryLists
.SelectMany(x => x.stateList)
.FirstOrDefault(x => x.name == passedInValue);

You can use SelectMany as other have pointed out (and I prefer that solution myself), however if you'd like the query syntax, you can use multiple from clauses (check the MSDN documentation for more examples):
var city = (from c in CountryLists
from city in c.stateList
where city.name == passedInValue
select city.name).FirstOrDefault();
It is equivalent to the SelectMany method solution, it uses it under the covers anyway.

Related

Return those records off some parents from which their children's certain property equals a certain value?

How to write this query? :
var parents = parents.Select(o => o.children.Where(p=>p.property1 == "Something")).ToList();
This comes up with the conversion type error. How can I return some parents based on a condition being true for their children's properties?
This is what your query could be:
parents = parents.Where(p => p.children.Any(c => c.property1 == "Something")).ToList();
Enumerable.Where filters a sequence of values based on a predicate whereas Enumerable.Select projects each element of a sequence into a new form.
Enumerable.Any would return true if there be at least 1 child with porperty1 equal to "something"
As all you need to do here is the filtering, you just need to use Where. You would have used Select if you wanted to create a collection of some type other than that of the parent itself.
Try Code
var parents= (from p in parents.AsEnumerable()
where p.children!=null && p.children.property1 =="Something"
select p).ToList()

LINQ Query comparing Id with an Id in a list inside SingleOrDefault query

I am trying to fetch an option using the SingleOrDefault Linq to SQL method.
var po = repository.Context.AsQueryable<Option>().SingleOrDefault(o => o.Option.Id == sp.Options // sp.Options is a collection);
The problem is that inside the SingleOrDefault method I am comparing p.Option.Id == a collection. What I want is to select the option from sp.Options that matches the o.Option.Id. How can I do that?
UPDATE:
One thing I should have mentioned that the sp.Options is a different class than the Option class. sp.Options is SPOptions class so I cannot pass it inside the contains method.
Take a look at Contains.
repository.Context.AsQueryable<Option>().SingleOrDefault(o => sp.Options.Contains(o.Option.Id));
If Options is not a collection of the class of Option.Id, you can use the Any method with your comparison logic in it as follow :
repository.Context.AsQueryable<Option>().SingleOrDefault(o => sp.Options.Any(opts => opts.Something == o.Option.Id));
Search using Contains (sp.Options.Contains(o.Option.Id)) like:
var po = repository.Context.AsQueryable<Option>()
.SingleOrDefault(o => sp.Options.Contains(o.Option.Id));
If members of sp.Options are different from Id then you can do:
var po = repository.Context.AsQueryable<Option>()
.SingleOrDefault(o => sp.Options.Any(r=> r.Id == o.Option.Id));
or
var po = repository.Context.AsQueryable<Option>()
.SingleOrDefault(o => sp.Options.Select(r=> r.Id).Contains(o.Option.Id));
Assuming Id is the field in sp.Options elements that you want to compare with.
Based on your question it seems you're expecting to have a single match between those two option sets, correct ?
If so, I'd suggest you to write it as:
var po = repository.Context.AsQueryable().Where(o => sp.Options.Any(item=>item.id == o.Option.Id)).SingleOrDefault();

Intersect two collections which contain different types

Suppose I have one collection, call it ids it is of type IEnumerable<string>, I have a second collection call it objects it's of type MyObject[]. MyObject has a string property called id. I would like a LINQ statement that returns all off the objects in the objects collection who's id matches any value in the ids collection. ids will be a strict subset of objects.Select(x => x.id). Meaning, for every string in ids I know there will be exactly one corresponding MyObject in objects. Can someone post a pure LINQ solution? I've tried a couple things with no luck. I can come up with an iterative solution easily enough so unless it's impossible to do with only LINQ please don't post any.
"Just" LINQ:
var r = obj.Where(o => ids.Any(id => id == o.id));
But better, for larger n, with a set:
var hs = new HashSet(ids);
var r = obj.Where(o => hs.Contains(o.id));
I think this is pretty straightforward with query syntax.
It would look something like:
var a = from o in objects
join i in ids on o.id equals i
select o;
If you just want a list of MyObject that match, you can do :
var solution = objects.Where(x=> ids.Contains(x.id));
With this instead, you'll get a List<T> where T is an Anonymous type with 2 properties, Id that is the string that work as "key" in this specific case, and Obj, a list of MyObject which id correspond to the Id property.
var solution = ids.Select(x=>new{ Id = x, Obj=objects.Where(y=>y.id == x).ToList()})
.ToList();
If you just want to know if there is any object in the intersection (which was what I was looking for)
Based on this
var a = from o in objects
join i in ids on o.id equals i
select o;
You can do this as well
var isEmpty = objects.Any(x => ids.Any(y => y == x.ToString()));
The accepted answer is correct. However, if someone doesn't like using SQL style LINQ, here is the LINQ extension method approach to solving the same problem.
var filteredObjects = objects.Join(ids, obj => obj.Id, id => id, (obj, _) => obj);
We are joining two different types, so the 2nd & 3rd Join parameter signify that join will be made on id.
The fourth parameter is used to select an object out of the resultant (obj, id) pair after applying join.

how do I return a filtered list using linq?

I'm not sure if my title is correct, but linq should pull the right experts in to help the title and answer the question.
If I have a list of People, how do I return a list of PeopleWrappers minus "Dave" and "Jane"?
query looks like this right now:
List<Person> People = CreatListofPersons();
People.Select(t => new PeopleWrapper(t)).ToArray();
People.Where( x => x.Name!="Dave" && x.Name!="Jane")
.Select(t => new PeopleWrapper(t))
.ToArray();
LINQ has a list of extension methods that allow you to filter or project (which you already to with Select()). In your case you can use Where() to specify which elements you want to let pass, in your example all persons whose name is neither Dave nor Jane.
does it matter if "Where" comes before
"Select" or after?
You typically want to filter as soon as you can, otherwise you will have to iterate and/or project over items you don't want to have anyway.
Conceptually though, yes, you can put there where() filter later but in your case you are dealing with a PeopleWrapper after you project with Select() - since the Where() extension method is using this data type as input its condition I don't think it would make much sense - you would filter people wrappers, not persons.
return People.Where(p => p.Name != "Dave" && p.Name != "Jane");
You can use Where to get just the elements that match a condition:
People.Where(p => p.name != "Dave" && p.name != "Jane" ).Select(t => new PeopleWrapper(t)).ToArray()

Location of XElement when querying over IEnumerable using LINQ

I have a linq query that is querying over IEnumberable. When I have a matching element for my where clause I would like to know the position of the element in the IEnumberable.
var result = from e in elements
where (string) e.Attribute("class") == "something"
select e.Position();
The e.Position() of course does not compile. The value of e.Position() would be the position of the selected element in the elements IEnumberable.
Any ideas on how to do this?
You need to use the overloaded Select method that allows for an index since that capability is not available in query syntax.
elements.Select((e, i) => new { Element = e, Index = i })
.Where(item => (string)item.Element.Attribute("class") == "something")
.Select(item => item.Index);
If you're using .NET 4.0 then you can use the (new) Zip method and write the same thing using the query syntax as well. It creates some temporary objects, so it isn't as efficient, but some people may find it more readable:
var result = from e in elements.Zip
(Enumerable.Range(0, elements.Count()), Tuple.Create)
where (string)e.Item1.Attribute("class") == "something"
select e.Item2;
It 'zips' the input collection with a generated sequence of numbers (with the same range as is the length of the collection). Then you can store the combined value either using the Tuple class (that's what I did) or you could use anonymous type.

Categories

Resources