.NET停止排序和Icompare()

时间:2017-10-03 16:13:46

标签: c# .net

我遇到排序和IComparer()的问题。我的程序停在它上面。我是C#的初学者。 以下是代码停止的部分:

public ArrayList ModelSort()
            {
                IComparer sorter = new R2SortHelper();
                InnerList.Sort(sorter);
                return InnerList;
            }

            private class R2SortHelper : System.Collections.IComparer
            {
                public int Compare(object x, object y)
                {
                    double m1 = ((Model)x).R2() + ((Model)x).Valid().GetHashCode();
                    double m2 = ((Model)y).R2() + ((Model)y).Valid().GetHashCode();

                    if (m1 > m2)
                        return -1;
                    else if (m1 < m2)
                        return 1;
                    else
                        return 0;
                }
            }

以下是来自控制台的错误:

Unable to sort because the IComparer.Compare() method returns inconsistent results. Either a value does not compare equal to itself, or one value repeatedly compared to another value yields different results. IComparer: 'AMO.EnPI.AddIn.Utilities.ModelCollection+R2SortHelper'.

例外情况:

例外文字

  

System.ArgumentException:无法排序,因为IComparer.Compare()方法返回不一致的结果。要么值不等于自身,要么重复一个值与另一个值进行比较会产生不同的结果。 IComparer:&#39; AMO.EnPI.AddIn.Utilities.ModelCollection + R2SortHelper&#39;。          在System.Array.SorterObjectArray.DepthLimitedQuickSort(Int32 left,Int32 right,Int32 depthLimit)          在System.Array.SorterObjectArray.DepthLimitedQuickSort(Int32 left,Int32 right,Int32 depthLimit)          在System.Array.Sort(数组键,数组项,Int32索引,Int32长度,IComparer比较器)          在System.Collections.ArrayList.Sort(Int32索引,Int32计数,IComparer比较器)          在System.Collections.ArrayList.Sort(IComparer comparer)          位于C:\ ENPI \ EnPI \ AMO.EnPI-5.0 \ AMO.EnPI.Utilities \ Analytics.cs中的AMO.EnPI.AddIn.Utilities.ModelCollection.ModelSort():第961行          位于C:\ ENPI \ EnPI \ AMO.EnPI-5.0 \ AMO.EnPI.AddIn \ ModelSheet.cs中的AMO.EnPI.AddIn.ModelSheet.WriteResultsTable(Int32 n,Boolean top):第146行          位于C:\ ENPI \ EnPI \ AMO.EnPI-5.0 \ AMO.EnPI.AddIn \ ModelSheet.cs中的AMO.EnPI.AddIn.ModelSheet.Populate():第60行          位于C:\ ENPI \ EnPI \ AMO.EnPI-5.0 \ AMO.EnPI.AddIn \ ThisAddIn.cs中的AMO.EnPI.AddIn.ThisAddIn.plotEnPI(ListObject LO):第318行          at AMO.EnPI.AddIn.RegressionControl.runFunction(Object sender,EventArgs e)位于C:\ ENPI \ EnPI \ AMO.EnPI-5.0 \ AMO.EnPI.AddIn \ RegressionControl.cs:第817行          at AMO.EnPI.AddIn.CO2EmissionControl.btnCalculate_Click(Object sender,EventArgs e)位于C:\ ENPI \ EnPI \ AMO.EnPI-5.0 \ AMO.EnPI.AddIn \ CO2EmissionControl.cs:第148行

我的模特课:

public class Model
    {
    public int ModelNumber { get; set; }
    public double[] Ys { get; set; }
    public double[,] Xs { get; set; }
    public string[] VariableNames { get; set; }

    public double RMSError { get; set; }

    public double[] Coefficients { get; set; }

    public Model()
    {
        ModelNumber = 0;
        Ys = null;
        Xs = null;
        VariableNames = null;
        RMSError = 0;
        Coefficients = null;
    }
    public Model(int ModelNumber, double[] Ys, double[,] Xs, string[] VariableNames)
    {
        RMSError = 0;
        Coefficients = null;

        // run LLS
        int info;
        double[] c;
        alglib.lsfitreport rep;
        try
        {
            alglib.lsfitlinear(Ys, Xsplusone(), out info, out c, out rep);
        }
        catch
        {
            throw;
        }

        Coefficients = c;
        RMSError = rep.rmserror;
    }

    public void Run() //double[] Ys, double[,] Xs, string[] VariableNames)
    {
        RMSError = 0;
        Coefficients = null;

        if (Ys != null && Xs != null)
        {
            // run LLS
            int info;
            double[] c;
            alglib.lsfitreport rep;
            try
            {
                alglib.lsfitlinear(Ys, Xsplusone(), out info, out c, out rep);
            }
            catch
            {
                throw;
            }

            Coefficients = c;
            RMSError = rep.rmserror;
        }
    }

    public int N()
    {
        return Ys.Count();
    }

    public int df()
    {
        return N() - k() - 1;
    }

    public int k()
    {
        return VariableNames.Count();
    }

    public double TotalSS()
    {
        // compute total sum of squares
        double ybar = Ys.Average();
        double sst = 0;
        for (int i = Ys.GetLowerBound(0); i <= Ys.GetUpperBound(0); i++)
        {
            sst += Math.Pow(Ys[i] - ybar, 2);
        }

        return sst;
    }

    public double ResidualSS ()
    {
        return ( N() * Math.Pow( RMSError, 2));
    }

    public double R2()
    {
        return (1 - (ResidualSS() / TotalSS()));
    }

    public double AdjustedR2()
    {
         return (1 - (((1 - R2()) * (N() - 1)) / (N() - k() - 1)));

    }

    public double F()
    {
        return ( (R2() / k()) / ((1 - R2()) / (N() - k() - 1)));
    }

    public double ModelPValue()
    {
        double modelP = 0;
        double modelF = F();
        if (modelF < 0) modelF = 0;

        try
        {
            modelP = alglib.fcdistribution(N() - df() - 1, df(), modelF);

        }
        catch (alglib.alglibexception e)
        {
        }
        return modelP;
    }

    public bool Valid()
    {
        // Model validity criteria, from the SEP M&V protocol:
        // The model p-value must be less than 0.1
        // All variables must have p-values less than 0.2
        // At least one variable must have a p-value of less than 0.1
        // The R2 value must be greater than 0.5

        double[] ps = PValues();
        bool varsvalid = true;
        bool varlowexists = false;

        for (int i = 0; i < ps.Count(); i++)
        {
            if (ps[i] <= Constants.PVALUE_THRESHOLD)
                varlowexists = true;
            if (ps[i] > Constants.PVALUE_HIGH)
                varsvalid = false;
        }

        if (!varlowexists)
            return false;

        if (!varsvalid)
            return false;

        if (ModelPValue() > Constants.PVALUE_THRESHOLD)
            return false;

        if (R2() < Constants.R2VALUE_MIN)
            return false;

        return true;

    }

    public string Formula()
    {
        string formula = "";
        int offset = Coefficients.GetLowerBound(0) - VariableNames.GetLowerBound(0);
        for (int i = Coefficients.GetLowerBound(0); i < Coefficients.GetUpperBound(0); i++)
        {
             formula += "(" + Coefficients[i].ToString("0.0000") + " * " + ExcelHelpers.CreateValidFormulaName(VariableNames[i - offset]) + ") + ";
            // formula += "(" + Coefficients[i].ToString() + " * " + ExcelHelpers.CreateValidFormulaName(VariableNames[i - offset]) + ") + ";
        }

        formula += Coefficients[Coefficients.GetUpperBound(0)].ToString("0.00");

        return formula;
    }

    public double[,] Xsplusone()
   {
       return DataHelper.arrayAddIdentity(Xs, 0, 1); // add on a column of ones for the intercept
   }

    public double[] PredictedYs()
   {            // compute the predicted ys
       double[] yhat = new double[N()];
       double[,] xs = Xsplusone();
       double[] c = Coefficients;

       for (int i = 0; i < N(); i++)
       {
           yhat[i] = 0;
           for (int j = 0; j < k() + 1; j++)
           {
               yhat[i] += xs[i, j] * c[j];
           }
       }

       return yhat;
   }

    public double[,] CovarianceMatrix()
   {
       // compute the coefficient covariance matrix
       double[,] twodYs = DataHelper.dbl2DArray(Ys);
       double[,] XYs = DataHelper.dblarrayUnion(Xs, twodYs);
       double[,] cov;
       int info;
       alglib.linearmodel lm;
       alglib.lrreport rpt;

       try
       {
           alglib.lrbuild(XYs, N(), k(), out info, out lm, out rpt);
           cov = rpt.c;
       }
       catch
       {
           throw;
       }

       return cov;
   }

    public double[] StandardErrors()
    {
       // compute the x std errors and p-values
       double[,] cov = CovarianceMatrix();
       double[] se = new double[k()];

       if (cov.GetLength(0) > 0 && cov.GetLength(1) > 0)
       {
           for (int j = 0; j < k(); j++)
           {
               se[j] = Math.Sqrt(cov[j, j]);
           }
       }

       return se;
   }

    public double[] PValues()
   {
       double[] c = Coefficients;
       double[,] cov = CovarianceMatrix();
       double[] se = StandardErrors();
       double[] pv = new double[k()];

       if (cov.GetLength(0) > 0 && cov.GetLength(1) > 0)
       {
           for (int j = 0; j < k(); j++)
           {
               se[j] = Math.Sqrt(cov[j, j]);
               try
               {
                   pv[j] = 2 * (1 - alglib.studenttdistribution(df(), Math.Abs(c[j] / se[j])));
               }
               catch
               {
               }
           }
       }

       return pv;
   }

    public string AICFormula()
    {
        return "";
    }

    //Added By Suman for SEP Validation changes
    public string[] SEPValidationCheck()
    {
        string[] sepChk = new string[k()];
        for (int cnt = 0; cnt < sepChk.Length; cnt++)
        {
            if (Valid() == true)
            {
                sepChk[cnt] = "Pass";
            }
            else
            {
                sepChk[cnt] = "Fail";
            }
        }
        return sepChk;
    }
}

这是GetHashCode():

public override int GetHashCode() 
        { 
            return x.GetHashCode() ^ y.GetHashCode(); 
        }

我的R2():

public double R2()
        {
            return (1 - (ResidualSS() / TotalSS()));
        }

2 个答案:

答案 0 :(得分:3)

对于大多数类型,您不能按GetHashCode()排序,因为哈希码计算不一定按照与值相同的顺序排序。只有在值本身(例如int)时才能可靠地对GetHashCode()进行排序,但此时在获取哈希码时没有任何意义,因为您已经拥有该值。你也没有显示R2()和Valid()方法的作用,所以谁知道那里发生了什么样的不利。

EDIT(OP更新代码):

您的GetHashCode()用法绝对不可排序。也没有在double中添加布尔值。 5 + 0 vs. 2 + 1不能正确排序(假设您想要预先设置这些错误?)

只需使用((Model)x).R2()vs((Model)y).R2()作为比较,如果你想要前面的falses或trues,你可以添加如下内容:

if (x.Valid && !y.Valid)
   return 1;
if (!x.Valid && y.Valid)
   return -1;

//then do your R2 comparisons here. 

该序言将导致非valid始终排在第一位,然后按R2排序。如果你想走另一条路,你可以倒转。

答案 1 :(得分:0)

你的.Valid()方法返回boolean,然后你去找哈希码。这是您的代码所期望的吗? 基本上,你正在做some double value + boolean.GetHashCode()。解决方法是在右侧表达式中不使用.Valid()。单独检查。

         private class R2SortHelper : System.Collections.IComparer
            {
                public int Compare(object x, object y)
                {
                    Model xModel = (Model)x;
                    Model yModel = (Model)y; 
                   if((Model.Valid()==true) && (yModel.Valid()==true))
                    { 
                    double m1 = xModel.R2() + xModel.GetHashCode();
                    double m2 = yModel.R2() + yModel.GetHashCode();
                    return (m1 > m2) ? -1 : ((m1 < m2) ? 1 :0);   
                    }
                   return 0;
               }
          }