How to Flatten Nested Objects with Linq Expression

How to flatten nested objects with linq expression

myBooks.SelectMany(b => b.Chapters
.SelectMany(c => c.Pages
.Select(p => b.Name + ", " + c.Name + ", " + p.Name)));

How to flatten nested objects (LINQ)

You can achieve it by creating a DataTable that yon can easily use as a source for the gridview. First add all columns and then for each stock add the warehouses:

var warehouseNames = 
stocks
.SelectMany(x => x.Warehouses.Select(y => y.WarehouseName)).Distinct();

var dt = new DataTable();
dt.Columns.Add("StockCode");

foreach (var name in warehouseNames)
{
dt.Columns.Add(name);
}

foreach (var stock in stocks)
{
var row = dt.NewRow();
row["StockCode"] = stock.Id;
foreach (var warehouse in stock.Warehouses)
{
row[warehouse.WarehouseName] = warehouse.Id;
}
dt.Rows.Add(row);
}

Warehouses

How to flatten nested objects with null leafs with linq expression

Using a string extension for quoting makes this cleaner:

public static class Ext {
public static string Quoted(this string text) => $"\"{text}\"";
}

You need to replace the null items with IEnumerable<>s that return a single null item like so:

var ans = myBooks.SelectMany(b => (b.Chapters == null ? new[] { (Chapter)null } : b.Chapters)
.SelectMany(c => (c?.Pages == null ? new[] { (Page)null } : c.Pages)
.Select(p => $"{b.Name.Quoted()}, {c?.Name?.Quoted() ?? "null"}, {p?.Name?.Quoted() ?? "null"}")
)
);

How to flatten nested dictionaries within Class using LINQ

Too many SelectMany:

var t = new TData(); // your TData

var aa = t.data.SelectMany(x =>
x.Value.innerData.Select(y => new
{
url = x.Key,
disp = x.Value.disp,
date = y.Key,
count = y.Value.count,
rank = y.Value.rank,
}));

The inner one must be a Select.

null output when flattening nested lists of objects with LINQ select many

I finally found a solution that works as I expected. It's not ideal and is honestly kinda ugly... but this is the only way I could find that did what I needed.

To sum it up, I needed to breakdown each SelectMany into its own statement where I grouped data by the various objects as needed, and from there it's just a series of joins to get the data as expected.

The code:

var uutData = results.Select(x => new UutData
{
UutResultId = x.Id,
...
}).ToList();

var stepData = results.SelectMany(x => (x.StepResults == null ? new List<StepResult>() : x.StepResults), (x, s) => new StepData
{
UutResultId = x.Id,
StepResultId = s.Id,
...
}).ToList();

var propData = stepData.SelectMany(s => (s.PropResults == null ? new List<PropResult>() : s.PropResults), (s, p) => new PropData
{
StepResultId = s.StepResultId,
PropResultId = p.Id,
...
}).ToList();

//... continue getting nested data objects as needed

var joined = from propStep in (from uutStep in (from uut in uutData
join step in stepData on uut.UutId equals step.UutResultId into step2
from subStep in step2.DefaultIfEmpty()
select new
{
uut.UutSerialNumber,
...
StepName = subStep == null ? "" : subStep.StepName,
...
StepResultId = subStep == null ? "" : subStep.StepResultId
})
join prop in propData on uutStep.StepResultId equals prop.StepResultId into prop2
from subProp in prop2.DefaultIfEmpty()
select new
{
uutStep.UutSerialNumber,
...
uutStep.StepResultId,
PropName = subProp == null ? "" : subProp.PropName,
...
PropResultId = subProp == null ? "" : subProp.PropResultId
})
//... continue joins as needed for all nested objects generated above
//appending data from each previous join to carry it all the way through to the final object
//to get objects back as List<object>, call .ToList() on entire query (use parentheses to encapsulate entire query)

Note that I inserted elipses where I was trying to shorten the code for this answer. The elipses just need to be replaced with all fields being added to the object.

After all the joins, the final returned List returns a top level object that contains all the relevant data from the nested objects that I needed. So the data is now no longer nested.

LINQ: How to convert the nested hierarchical object to flatten object

If you want it to flatten an arbitrarily deep tree of people, I suggest the following:

public IEnumerable<Person> GetFamily(Person parent)
{
yield return parent;
foreach (Person child in parent.Children) // check null if you must
foreach (Person relative in GetFamily(child))
yield return relative;
}

There isn't really any good way to shorten this with LINQ, because anonymous lambdas can't call themselves recursively without implementing Y. You could "reduce" the above method to

return parent.Children.SelectMany(p => GetFamily(p))
.Concat(new Person[] { parent });

or alternatively

yield return parent;
foreach (Person relative in parent.Children.SelectMany(GetFamily))
yield return relative;

but that seems sort of unnecessary to me.

SelectMany to flatten a nested structure

This is a naturally recursive problem. Using a recursive lambda, try something like:

Func<Node, IEnumerable<Node>> flattener = null;
flattener = n => new[] { n }
.Concat(n.Nodes == null
? Enumerable.Empty<Node>()
: n.Nodes.SelectMany(flattener));

Note that when you make a recursive Func like this, you must declare the Func separately first, and set it to null.

You could also flatten the list using an iterator-block method:

public static IEnumerable<Node> Flatten(Node node)
{
yield return node;
if (node.Nodes != null)
{
foreach(var child in node.Nodes)
foreach(var descendant in Flatten(child))
yield return descendant;
}
}

Either way, once the tree is flattened you can do simple Linq queries over the flattened list to find nodes:

flattener(node).Where(n => n.Type == myType);

Response adapted from: https://stackoverflow.com/a/17086572/1480391

LINQ - Flatten nested sequence so it is joined with the parent sequence

Use this:

from x in specializedContents
let t = x.GetType()
from i in t.GetInterfaces()
select new { Type = t.Name, Interface = i.Name };


Related Topics



Leave a reply



Submit