使用LINQ按前任(或父)元素索引排序无序元素列表的最快方法是什么?
每个元素都有一个唯一的ID和该元素的前任(或父)元素的ID,从中可以构建链表以表示有序状态。
ID | Predecessor's ID
--------|--------------------
20 | 81
81 | NULL
65 | 12
12 | 20
120 | 65
排序顺序为{81,20,12,65,120}。一个(有序的)链表可以很容易地从这些元素中迭代地组装,但它可以用更少的LINQ语句来完成吗?
编辑:我应该指定ID不一定是顺序的。为简单起见,我选择了1到5。查看随机的更新元素索引。
答案 0 :(得分:4)
假设“index”与排序(只是一个ID)无关,那么就这样声明:
public class Node
{
public int ID { get; set; }
public int? PredID { get; set; }
}
然后你可以建立一个从前任到后继的地图,然后按照链接。然而,这不是纯 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 +它的前任索引,这很容易递归地指定。当然,基础,案例是头 - 一个节点,其前身的ID为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));
}
通过首先创建从后继者到前任者的映射,可以在某种程度上改进第二个解决方案 。尽管如此,它仍然无法满足要求。
编辑:将第一个解决方案转换为迭代器块。
答案 1 :(得分:-1)
为了排序节点链接的事实是无关紧要的,只有id很重要。在这种情况下,你可以使用OrderBy,在这种情况下,将nullable int放在顶部,然后按升序排序。
public class ListNode
{
public int Id { get; set; }
public int? Predecessor { get; set; }
}
List<ListNode> myList = new List<ListNode> {
new ListNode() { Id = 2, Predecessor = 1},
new ListNode() { Id = 1, Predecessor = null},
new ListNode() { Id = 5, Predecessor = 4},
new ListNode() { Id = 3, Predecessor = 2},
new ListNode() { Id = 4, Predecessor = 3}};
var sortedbyPredecessor = myList.OrderBy(n => n.Predecessor).ToList();