C# 带元件复制的分拣集-can';不要删除元素

C# 带元件复制的分拣集-can';不要删除元素,c#,unity3d,sortedset,C#,Unity3d,Sortedset,我正在用C#in Unity实现A-star算法 我需要评估节点的集合: class Node { public Cell cell; public Node previous; public int f; public int h; public Node(Cell cell, Node previous = null, int f = 0, int h = 0) {

我正在用C#in Unity实现A-star算法

我需要评估节点的集合

class Node
    {
        public Cell cell;
        public Node previous;
        public int f;
        public int h;

        public Node(Cell cell, Node previous = null, int f = 0, int h = 0)
        {
            this.cell = cell;
            this.previous = previous;
            this.f = f;
            this.h = h;
        }
    }
我有一个SortedSet,它允许我存储几个节点,按h属性排序。不过,我需要能够存储具有相同h属性的两个节点。因此,我实现了一个特定的IComparer,它允许我按照h属性进行排序,并且仅当两个节点代表完全相同的单元时才触发相等

class ByHCost : IComparer<Node>
    {
        public int Compare(Node n1, Node n2)
        {
            int result = n1.h.CompareTo(n2.h);
            result = (result == 0) ? 1 : result;
            result = (n1.cell == n2.cell) ? 0 : result;
            return result;
        }
    }
在这里,removeWhere方法似乎找到了匹配项,但没有删除节点。 我试过另一种方法:

 Node worseNode = openSet.SingleOrDefault(n => {
      bool isSame = n.cell == candidateNode.cell;
      bool hasWorseCost = n.f > candidateNode.f;
      return isSame && hasWorseCost;
 });

 if(isCell127)
 {
      Debug.Log($"does worseNode exists ? {worseNode != null}"); // Debug returns true, it does exist.
 }

 if(worseNode != null)
 {
      if(isCell127)
      {
          Debug.Log($"openSet length {openSet.Count}"); // 10
      }
      openSet.Remove(worseNode);
      if(isCell127)
      {
          Debug.Log($"openSet length {openSet.Count}"); // 10 - It should have been 9.
      }
 }
我认为这个问题与我非常不寻常的IComparer有关,但我不清楚到底是什么问题


另外,我想知道使用自动排序集而不是手动排序列表是否有显著的性能改进,特别是在a-star算法用例中。

如果我编写您的测试,您会:

          n1.h < n2.h
          n1.cell = n2.cell -> final result = 0

          n1.h > n2.h
          n1.cell = n2.cell -> final result = 0 

          n1.h = n2.h
          n1.cell != n2.cell -> final result = 1      

          n1.h < n2.h
          n1.cell != n2.cell -> final result = -1  

          n1.h > n2.h
          n1.cell != n2.cell -> final result = 1 
n1.h最终结果=0
n1.h>n2.h
n1.单元=n2.单元->最终结果=0
n1.h=n2.h
n1.电池!=n2.单元->最终结果=1
n1.h最终结果=-1
n1.h>n2.h
n1.电池!=n2.单元->最终结果=1
当h值相等(测试编号3)时,您选择始终具有相同的结果->1。因此,你必须在电池上进行另一次测试以澄清位置,因为与给出相同结果的其他测试(测试编号5)存在混淆

所以我可以用样品来测试,但我很确定你打破了这个分类


因此,如果您澄清了测试,我建议您使用Linq并列出它的最佳性能。

如果我编写您的测试,您可以:

          n1.h < n2.h
          n1.cell = n2.cell -> final result = 0

          n1.h > n2.h
          n1.cell = n2.cell -> final result = 0 

          n1.h = n2.h
          n1.cell != n2.cell -> final result = 1      

          n1.h < n2.h
          n1.cell != n2.cell -> final result = -1  

          n1.h > n2.h
          n1.cell != n2.cell -> final result = 1 
n1.h最终结果=0
n1.h>n2.h
n1.单元=n2.单元->最终结果=0
n1.h=n2.h
n1.电池!=n2.单元->最终结果=1
n1.h最终结果=-1
n1.h>n2.h
n1.电池!=n2.单元->最终结果=1
当h值相等(测试编号3)时,您选择始终具有相同的结果->1。因此,你必须在电池上进行另一次测试以澄清位置,因为与给出相同结果的其他测试(测试编号5)存在混淆

所以我可以用样品来测试,但我很确定你打破了这个分类


因此,如果您澄清了测试,我建议您使用Linq并列出它的最佳性能。

我将回答我自己的主题,因为我有一个非常完整的主题

比较

IComparer界面的比较需要遵循一些规则。正如@frenchy所说,我自己的比较被打破了。以下是我完全忘记的比较的数学基础(我发现了它们):

在我的例子中,规则4——符号——被打破了

我需要存储具有相同h属性的多个节点,但也需要根据该h属性进行排序。所以,当h属性相同时,我需要避免相等

我决定做的不是在h比较结果为0(这违反了第四条规则)时使用默认值,而是以一种不会导致每个节点实例的唯一值为0的方式优化比较。好吧,这个实现可能不是最好的,也许有更好的方法来实现一个独特的价值,但下面是我所做的

private class Node
{
   private static int globalIncrement = 0;

   public Cell cell;
   public Node previous;
   public int f;
   public int h;
   public int uid;

   public Node(Cell cell, Node previous = null, int f = 0, int h = 0)
   {
       Node.globalIncrement++;

       this.cell = cell;
       this.previous = previous;
       this.f = f;
       this.h = h;
       this.uid = Node.globalIncrement;
   }
}

private class ByHCost : IComparer<Node>
{
   public int Compare(Node n1, Node n2)
   {
       if(n1.cell == n2.cell)
       {
           return 0;
       }

       int result = n1.h.CompareTo(n2.h);
       result = (result == 0) ? n1.uid.CompareTo(n2.uid) : result; // Here is the additional comparison which never lead to 0. Depending on use case and number of object, it would be better to use another system of unique values.
       return result;
   }
}
私有类节点
{
私有静态int globalIncrement=0;
公共小区;
公共节点前向;
公共INTF;
公共INTH;
公共信息;
公共节点(单元格,节点previous=null,int f=0,int h=0)
{
Node.globalIncrement++;
这个细胞=细胞;
this.previous=先前;
这个。f=f;
这个,h=h;
this.uid=Node.globalIncrement;
}
}
私有类ByHCost:IComparer
{
公共整数比较(节点n1、节点n2)
{
if(n1.单元==n2.单元)
{
返回0;
}
int结果=n1.h.与(n2.h)相比;
result=(result==0)?n1.uid.CompareTo(n2.uid):result;//这是一个不会导致0的额外比较。根据用例和对象数量,最好使用另一个唯一值系统。
返回结果;
}
}
删除where方法


RemoveWhere使用谓词查看集合,因此我认为它不关心比较。但是RemoveWhere使用内部Remove方法,它确实关心比较。因此,即使RemoveWhere找到了一个元素,如果您的比较不重要,它也会悄悄地通过。这是一个非常奇怪的实现,不是吗?

我将回答我自己的主题,因为我有一个非常完整的主题

比较

IComparer界面的比较需要遵循一些规则。正如@frenchy所说,我自己的比较被打破了。以下是我完全忘记的比较的数学基础(我发现了它们):

在我的例子中,规则4——符号——被打破了

我需要存储具有相同h属性的多个节点,但也需要根据该h属性进行排序。所以,当h属性相同时,我需要避免相等

我决定做的不是在h比较结果为0(这违反了第四条规则)时使用默认值,而是以一种不会导致每个节点实例的唯一值为0的方式优化比较。好吧,这个实现可能不是最好的,也许有更好的方法来实现一个独特的价值,但下面是我所做的

private class Node
{
   private static int globalIncrement = 0;

   public Cell cell;
   public Node previous;
   public int f;
   public int h;
   public int uid;

   public Node(Cell cell, Node previous = null, int f = 0, int h = 0)
   {
       Node.globalIncrement++;

       this.cell = cell;
       this.previous = previous;
       this.f = f;
       this.h = h;
       this.uid = Node.globalIncrement;
   }
}

private class ByHCost : IComparer<Node>
{
   public int Compare(Node n1, Node n2)
   {
       if(n1.cell == n2.cell)
       {
           return 0;
       }

       int result = n1.h.CompareTo(n2.h);
       result = (result == 0) ? n1.uid.CompareTo(n2.uid) : result; // Here is the additional comparison which never lead to 0. Depending on use case and number of object, it would be better to use another system of unique values.
       return result;
   }
}
私有类节点
{
私有静态int globalIncrement=0;
公共小区;
公共节点前向;
公共INTF;
公共INTH;
公共信息;
公共节点(单元,节点previous=null,int f=0,i