1

我有一个包含大量字符串的 ArrayList。它需要根据NameAgeAmt三个字段(基本上是三个子字符串)进行就地排序。Age是第一个子字符串(位置 0-3),Name是第二个(3-6),Amt是最后一个(6-10)。这些参数的排序顺序非常重要,如下所示:

首先按Name执行升序排序,然后按Age升序排序(实际上在子字符串中更早),然后按Amt降序排序。就是这样。

我有这门课

public class ArrComparer : IComparer
{
    public int Compare(object x, object y)
    {
        string left = x.ToString();
        string right = y.ToString();
        string lhs = left.Substring(3, 6);
        string rhs = right.Substring(3, 6);
        return lhs.CompareTo(rhs);
    }
}

我使用它仅基于一个字段进行排序 - 通过调用命名

RecordList.Sort(new ArrComparer());

这让我可以根据该字段正确排序。问题是如何修改此代码以允许我根据所有三个AT ONCE以正确的顺序并使用正确的 asc/desc 模式进行排序?

任何代码或提示将不胜感激。(顺便说一句,如果您想知道List<T>在这个项目中使用泛型不是一个选项)。

4

5 回答 5

6

ArrayList 仍然实现 IEnumerable,这意味着您可以在 linq 中使用简单的 orderby() 和 thenby() 扩展:

RecordList = new ArrayList(
         RecordList.Cast<string>().OrderBy(s => s.Substring(3,3))
                   .ThenBy(s => int.Parse(s.Substring(0,3)))
                   .ThenByDescending(s => double.Parse(s.Substring(6,4)))
          .ToArray());

表达这一点的其他方法包括构建更复杂的 .OrderBy() 或使用匿名类型将字符串组合为对象:

RecordList = new ArrayList(
       Record.Cast<string>().Select(s => new {source = s, age = int.Parse(s.Substring(0, 3)), name = s.Substring(3,3), amt = double.Parse(s.Substring(6,4))})
             .OrderBy(o => o.name)
             .ThenBy(o => o.age)
             .ThenByDescending(o => o.amt)
          .Select(o => o.source).ToArray());

我喜欢这个选项,因为它让你开始思考对象。正确地玩你的牌,你可以跳过最后一个 .Select() 投影以保留对象而不是返回到字符串,这将节省以后必须重新进行所有解析的工作

如果这些不是一个选项(可能出于同样的原因,您不能使用 List<T>),那么很容易修改现有的比较方法,如下所示:

public class ArrComparer : IComparer
{
    public int Compare(object x, object y)
    {
        int result;
        string left = x.ToString();
        string right = y.ToString();
        string lhs1 = left.Substring(3, 3);
        string rhs1 = right.Substring(3, 3);
        result = lhs1.CompareTo(rhs1);

        if (result == 0)
        {
           int lhs2 = int.Parse(left.Substring(0,3));
           int rhs2 = int.Parse(right.Substring(0,3));
           result = lhs2.CompareTo(rhs2);
        }

        if (result == 0)
        {
            double lhs3 = double.Parse(left.Substring(6,4));
            double rhs3 = double.Parse(right.Substring(6,4));
            result = rhs3.CompareTo(lhs3);
        }

        return result;
    }
}
于 2011-03-15T19:50:24.173 回答
2

您可以逐个比较:

string left = (string)x;
string right = (string)y;

string lname = left.Substring(3, 3);
string rname = right.Substring(3, 3);
int result = lname.CompareTo(rname);
if (result != 0) return result;

string lage = left.Substring(0, 3);
string rage = right.Substring(0, 3);
int result = lage.CompareTo(rage);
if (result != 0) return result;

string lamt = left.Substring(6);
string ramt = right.Substring(6);
return -lamt.CompareTo(ramt);
于 2011-03-15T19:50:57.327 回答
1

如果您需要 IComparer,请尝试以下操作:

public class ArrComparer : IComparer
{
  public int Compare(object x, object y)
  {
    string left = x.ToString();
    string right = y.ToString();
    string leftName = left.Substring([whatever]);
    string rightName = right.Substring([whatever]);

    // First try comparing names
    int result = leftName.CompareTo(rightName);
    if (result != 0)
    {
      return result;
    }

    // If that didn't work, compare ages
    string leftAge = left.Substring([whatever]);
    string rightAge = right.Substring([whatever]);
    result = leftAge.CompareTo(rightAge);
    if (result != 0)
    {
      return result;
    }    

    // Finally compare amounts (descending)
    string leftAmt = left.Substring([whatever]);
    string rightAmt = right.Substring([whatever]);
    result = -leftAmt.CompareTo(rightAmt); // Minus for descending

    return result;
  }
}
于 2011-03-15T19:51:56.170 回答
1

我建议将您的记录存储在一个对象中,并改为使它们具有可比性。

为了使用您当前使用的相同方法比较所有三个字段,您只需提取所有三个数据并进行完整比较。

public class ArrComparer : IComparer
{
    public int Compare(object x, object y)
    {
        string left = x.ToString();
        string right = y.ToString();

        // Note I assumed indexes since yours were overlapping.
        string lage = left.Substring(0, 3);
        string lname = left.Substring(3, 3);
        string lamt = left.Substring(7, 3);

        string rage = left.Substring(0, 3);
        string rname = left.Substring(3, 3);
        string ramt = left.Substring(7, 3);

        // Compare name first, if one is greater return
        int result = lname.CompareTo(rname);
        if (result != 0)
            return result;

        // else compare age, if one is greater return
        result = lage.CompareTo(rage)
        if (result != 0)
            return result;

        // else compare amt if one is greater return
        result = lamt.CompareTo(ramt)
        if (result != 0)
            return result;

        // else they are equal
        return 0;
    }
}
于 2011-03-15T19:52:16.763 回答
0

你可以用 if(rhs == lhs) 这样的 if 语句来扩展你的 ArrCompare 与字符串的其他部分。Accen deccend 是返回 -1 或 1 的交汇点

于 2011-03-15T19:49:52.993 回答