数组列表排序

发布于 2024-10-21 20:40:47 字数 965 浏览 1 评论 0原文

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

首先按名称升序排序,然后按升序排序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());

这可以让我根据该一个字段进行正确排序。问题是如何修改此代码以允许我按正确的顺序并使用正确的升序/降序模式基于所有三个一次进行排序?

任何代码或提示将不胜感激。 (顺便说一句,如果您想知道在该项目中不可以选择使用通用 List)。

I have an ArrayList that contains a large number of strings. It needs to be sorted in place based on three fields (essentially three substrings) which are Name, Age and Amt. Age is the first substring (position 0-3), Name is second (3-6) and Amt is last (6-10). The order in which these parameters are to be sorted is very important and is as follows:

First perform ascending sort by Name THEN do ascending sort by Age (which actually comes earlier in the substring) and THEN do descending sort by Amt. That's it.

I have this class

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);
    }
}

which I use to sort based on just one field - Name by invoking

RecordList.Sort(new ArrComparer());

This lets me sort correctly based on that one field. The question is how can I modify this code to allow me to sort based on all three AT ONCE, in the right order and using proper asc/desc mode?

Any code or tips would be greatly appreciated. (By the way, in case you are wondering using generic List<T> is not an option in this project).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

橘虞初梦 2024-10-28 20:40:47

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());

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

如果这些不是一个选项(可能出于同样的原因您不能使用 List),则可以轻松修改现有的比较方法,如下所示:

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;
    }
}

ArrayList still implements IEnumerable, meaning you can use the simple orderby() and thenby() extensions in linq:

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());

Other ways to express this include building a more complicated .OrderBy() or using an anonymous type to compose your string as an object:

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());

I like that option because it sets you up to start thinking in terms objects. Play your cards right and you can skip that last .Select() projection to keep the objects rather than going back to strings, which will save the work of having to do all that parsing over again later.

If these aren't an option (possibly for the same reason you can't use List<T>), it's easy to modify your existing compare method like so:

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;
    }
}
最终幸福 2024-10-28 20:40:47

您可以逐个比较:

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);

You can compare part by part:

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);
泼猴你往哪里跑 2024-10-28 20:40:47

如果您需要 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;
  }
}

If you need an IComparer, try something like:

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;
  }
}
傾城如夢未必闌珊 2024-10-28 20:40:47

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

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

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;
    }
}

I would recommend storing your records in an object, and make those comparable instead.

In order to compare all three fields using the same method you are currently using you simply need to extract all three pieces of data and do a full comparison.

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;
    }
}
桃酥萝莉 2024-10-28 20:40:47

您可以将 ArrCompare 与 if 语句(例如 if(rhs == lhs) compere)与字符串的其他部分一起使用。
Accen Decend 是 return -1 或 1 的满足者

you could expend your ArrCompare with if statements like if(rhs == lhs) compere with other part of string.
Accen deccend is meeter of return -1 or 1

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文