Not the best LINQ candidate, however, this recursive extension should work:
public static IEnumerable<T> Traverse<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> fnRecurse)
{
foreach (T item in source)
{
yield return item;
IEnumerable<T> seqRecurse = fnRecurse(item);
if (seqRecurse != null)
{
foreach (T itemRecurse in Traverse(seqRecurse, fnRecurse))
{
yield return itemRecurse;
}
}
}
}
Here's your sample data:
DataTable tbldata = new DataTable();
tbldata.Columns.Add("ID", typeof(int));
tbldata.Columns.Add("PrID", typeof(int));
tbldata.Columns.Add("Name", typeof(string));
tbldata.Rows.Add(1, null, "N1");
tbldata.Rows.Add(2, 1, "N2");
tbldata.Rows.Add(3, 2, "N3");
tbldata.Rows.Add(4, 3, "N4");
This query returns your desired result:
string parentName = "N1";
IEnumerable<DataRow> rows = tbldata.AsEnumerable();
DataRow parentRow = rows.FirstOrDefault(r => r.Field<string>("Name") == parentName);
DataRow lastChild = null;
if(parentRow != null)
{
int parentID = parentRow.Field<int>("ID");
lastChild = rows.Where(r => r.Field<int?>("PrID") == parentID)
.Traverse(parent => rows
.Where(child => child.Field<int?>("PrID") == parent.Field<int>("ID")))
.LastOrDefault();
}
Output:
Console.Write(String.Join(",", lastChild.ItemArray)); // 4,3,N4