Предполагая, что «index» не имеет ничего общего с упорядочением (просто ID), скажем, объявлено так:
public class Node
{
public int ID { get; set; }
public int? PredID { get; set; }
}
Тогда вы можете построить карту от предшественника к преемнику, а затем перейти по ссылкам. Это не pure LINQ, однако, но читабельное и довольно эффективное:
public static LinkedList<int> GetLinkedList(IEnumerable<Node> nodes)
{
if(nodes == null)
throw new ArgumentNullException("nodes");
return new LinkedList<int>(GetOrderedNodes(nodes.ToList()));
}
private static IEnumerable<int> GetOrderedNodes(IEnumerable<Node> nodes)
{
// Build up dictionary from pred to succ.
var links = nodes.Where(node => node.PredID != null)
.ToDictionary(node => node.PredID, node => node.ID);
// Find the head, throw if there are none or multiple.
var nextId = nodes.Single(node => node.PredID == null).ID;
// Follow the links.
do
{
yield return nextId;
} while (links.TryGetValue(nextId, out nextId));
}
РЕДАКТИРОВАТЬ : Вот ужасно неэффективное, но функциональное решение.
Идея состоит в том, что индекс элемента должен быть 1 + индекс его предшественника, который легко определить рекурсивно. Основой, случаем, конечно же, является голова - узел, чей идентификатор предшественника равен null
.
static LinkedList<int> GetLinkedList(IEnumerable<Node> nodes)
{
return new LinkedList<int>
( from node in nodes
orderby GetIndex(nodes, node)
select node.ID
);
}
static int GetIndex(IEnumerable<Node> nodes, Node node)
{
return node.PredID == null ? 0 :
1 + GetIndex(nodes, nodes.Single(n => n.ID == node.PredID));
}
Можно улучшить второе решение до некоторой степени , сначала создав карту от преемника к предшественнику. Тем не менее, это нигде не так эффективно, как императивное решение.
EDIT : Превратило первое решение в блок итератора.