LINQ - Getting all child records from all parents - c#

I have two models:
class Foo
{
public List<Bar> Bars { get; set; }
}
class Bar
{
public int Value { get; set; }
}
Having an instance of List<Foo>, how can I get all Value using a LINQ query?
Thank you all

SelectMany is normally the way to flatten hierarchies, so:
var values = myList.SelectMany(foo => foo.Bar)
.Select(bar => bar.Value);
The SelectMany will give you an IEnumerable<Bar>, and then the Select projects that sequence of Bar objects to the Value property of each, returning an IEnumerable<int>.
As a query expression, this would be:
var values = from foo in myList
from bar in foo.Bar
select bar.Value;

I suggest you to change List<Bar> property name to Bars.
And firstly use SelectMany(). It projects each element of a sequence to an IEnumerable<T> and flattens the resulting sequences into one sequence. And then use Select() to project each element of a new sequence as you wish.
var result = myList.SelectMany(x => x.Bars).Select(x => x.Value).ToList();

Use SelectMany instead of Select
var result = LIST1.SelectMany(x => x.LIST2.Select(y => y.Value)).Tolist();

Related

Linq: Select KeyValuePair from dictionary where value is a list of objects

I have a field that looks like:
public Dictionary<ClassA, List<ClassB>> MyDict;
Assume that:
public class ClassA
{
public string Name;
public int Id;
}
public class ClassB
{
public string Tag;
public string Text;
}
I'm trying to define a query that is of IEnumerable<KeyValuePair<ClassA,IEnumerable<ClassB>> type where I define a condition on the value of ClassB.Tag. I tried things like:
IEnumerable<KeyValuePair<ClassA,IEnumerable<ClassB>> q =
MyDict.Where(pair => pair.Value.Any(b => b.Tag == "a tag"));
But obviously the above is not what I need because it returns the whole List<ClassB> if any item matches that condition, while what I want is to return an IEnumrable or a List of items that match the condition.
dotNetFiddle demo
You need to construct the IEnumerable from a call to ToDictionary, where you use a projection to only take the matching BClass from the list and only take the result from that set where values in the BClass list were actually matched.
IEnumerable<KeyValuePair<ClassA,List<ClassB>>> q = MyDict.ToDictionary(
k => k.Key,
k => k.Value.Where(b => b.Tag == "10").ToList()
).Where(kv => kv.Value.Any());

How to get distinct values from nested lists of objects?

I have the following problem:
foo f = new foo();
// ...
f.bars.SelectMany(m => m.qux.GroupBy(x => x.hash))
.Select(group => group.First())
.Sum(s => s.size);
This returns the sum of the total size property for qux within a single bar instance. Adding another qux object with an existing hash value in another bar is ignored so its size value is counted in the computed sum. (Even tho the same qux exists in another bar object).
How can I tweak my query to make sure all objects having the same hash are calculated once?
The data structure would look like this:
class foo
{
public List<bar> bars = new List<bar>();
}
class bar
{
public List<qux> qux = new List<qux>();
}
class qux
{
public string hash { get; set; }
public int size { get; set; }
}
Judging from your data structure, here is what you need:
int sizeSum =
bars.SelectMany(m => m.qux)
.GroupBy(q => q.hash)
.Select(g => g.First())
.Sum(q => q.size);
The difference with your initial solution is that we first get a unified list with .SelectMany(), and only then do we group it by hash.

Is there a way to select two values into same IEnumerable using LINQ in C#?

I have a class that has two integers in it, for example A and B:
public class MyClass {
public int A { get; set; }
public int B { get; set; }
...other stuff...
}
I have a MyCollection of type ObservableCollection<MyClass> in code, and have a need to get an IEnumerable<int> of ALL the values -- both A's and B's -- together in one list.
I have figured out how to do it with quite verbose code (significantly simplified to be only one level below for example purposes, but actually 3 levels of "from" calls and selecting values from within nested lists):
IEnumerable<int> intsA=
(from x in MyCollection
select x.A);
IEnumerable<int> intsB =
(from x in MyCollection
select x.B);
IEnumerable<int> allInts = intsA.Concat(intsB);
It seems like there should be a way to select both variables at the same time into the same IEnumerable<int>. Obviously below doesn't work, but I'd love something like
IEnumerable<int> allInts = (from x in MyCollection select x.A, x.B);
Does something like this exist that is more elegant than what I have above?
I found how to select multiple values into an anonymous type here, but that doesn't make it into the same IEnumerable and still requires more code/processing to get the items out.
(BTW, using .NET 4.5.1, if that makes a difference.) Thanks!
You could use SelectMany:
var result = source.SelectMany(x => new[] { x.A, x.B });
But because you'd allocate a new array for each object, I don't know how performance it will be (or maybe you don't care about it that much).
You could declare GetIntValues on your type which would return IEnumerable<int>:
public class MyClass {
public int A { get; set; }
public int B { get; set; }
...other stuff...
public IEnumerable<int> GetIntValues()
{
yield return A;
yield return B;
}
}
And use it like this:
var result = source.SelectMany(x => x.GetIntValues());
But there is still an additional allocation for each element.
That's pretty easy indeed:
IEnumerable<int> allInts = MyCollection.Select(i => i.A)
.Concat(MyCollection.Select(i => i.B));
It's equivalent to what you wrote, but less verbose. It's using the lambda syntax instead of query comprehension syntax.
Use it if you want to avoid additional allocations. If you don't care about GC pressure, Marcin's solution is even shorter. Also, this outputs the elements in a different order than his solution.

find inside array of objects

i have a objectA
public class objectA
{
public int Id;
public string Name;
}
i have a list of objectA
List<objectA> list;
i want to find in the list any objectA with Id = 10;
is there linq syntax for this or do i simply have to write a loop here.
list.Where(o => o.Id == 10);
Remember: you can chain those method calls, or you can use the IEnumerable returned here for things like databinding.
To return all objects with an Id of ten, you'll need:
list.Where(o => o.Id = 10)

LINQ - Select correct values from nested collection

Consider the following class hierarchy:
public class Foo
{
public string Name { get; set; }
public int Value { get; set; }
}
public class Bar
{
public string Name { get; set; }
public IEnumerable<Foo> TheFoo { get; set; }
}
public class Host
{
public void Go()
{
IEnumerable<Bar> allBar = //Build up some large list
//Get Dictionary<Bar, Foo> with max foo value
}
}
What I would like to do using Linq2Objects is to get an KeyValuePair where for each Bar in the allBBar collection we select the Foo with the maximum Value property. Can this be done easily in a single LINQ statement?
Sure, although my preferred solution uses MaxBy from MoreLINQ:
var query = allBar.ToDictionary(x => x, // Key
x => x.TheFoo.MaxBy(f => f.Value));
Note that this will go pear-shaped if TheFoo is empty for any Bar instance.
Another way using Aggregate instead of OrderBy so that figuring out the max Foo is O(n) instead of O(n log n):
var query = allBar.ToDictionary(
bar => bar,
bar => bar.TheFoo.Aggregate(
null,
(max, foo) => (max == null || foo.Value > max.Value) ? foo : max));
just to add to Jon's comment about MaxBy going pear shaped if you have no foos, you could do an OrderByDescending and then use FirstOrDefault to get at the Max element. If the collection is empty it'd just return null instead of going "pear shaped".
var foobars = bars.ToDictionary(bar => bar,
bar => bar.TheFoo.OrderByDescending(foo => foo.Value).FirstOrDefault());
I don't think this wouldn't be as efficient as MaxBy, but it'd be more robust in the case of an empty collection.

Categories

Resources