如何使用C#在数字子字符串上排序字符串列表 [英] How to order list of strings on number substring using C#

查看:361
本文介绍了如何使用C#在数字子字符串上排序字符串列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个字符串列表,每个字符串都包含一个数字子字符串,我希望根据该子字符串的数值对其进行重新排序.该集合看起来像这样,但更大:

I have a list of strings, each containing a number substring, that I'd like to be reordered based on the numerical value of that substring. The set will look something like this, but much larger:

List<string> strings= new List<string>
{
    "some-name-(1).jpg",
    "some-name-(5).jpg",
    "some-name-(5.1).jpg",
    "some-name-(6).jpg",
    "some-name-(12).jpg"
};

数字将始终被括号括起来,括号是字符串中唯一的括号,因此使用String.IndexOf是可靠的.请注意,不仅可能会缺少数字,而且还会有小数,而不仅仅是整数.

The number will always be surrounded by parentheses, which are the only parentheses in the string, so using String.IndexOf is reliable. Notice that not only may there be missing numbers, but there can also be decimals, not just integers.

我很难获得一个重新排序的相同字符串的列表,这些字符串已经在该子字符串的数值上进行了排序.有没有人有办法做到这一点,希望它表现良好?谢谢.

I'm having a really tough time getting a reordered list of those same strings that has been ordered on the numerical value of that substring. Does anyone have a way of doing this, hopefully one that performs well? Thanks.

推荐答案

这将检查括号之间的项目是否可转换为double,如果不是,则在这种情况下将返回-1.

This will check if the items between the parenthesis is convertible to a double, if not it will return -1 for that case.

var numbers = strings.Select( x => x.Substring( x.IndexOf( "(" ) + 1, 
    x.IndexOf( ")" ) - x.IndexOf( "(" ) - 1 ) ).Select( x =>
{
   double val;
   if( double.TryParse( x, out val ) ) {
      return val;
   }

   // Or whatever you want to do
   return -1;
} ).OrderBy( x => x ); // Or use OrderByDescending

如果您确定括号之间总会有一个数字,请使用较短的数字:

If you are sure there will always be a number between the parenthesis, then use this as it is shorter:

var numbers = strings.Select( 
   x => x.Substring( x.IndexOf( "(" ) + 1, x.IndexOf( ")" ) - x.IndexOf( "(" ) - 1 ) )
   .Select( x => double.Parse(x))
.OrderBy( x => x ); // Or use OrderByDescending

编辑

我需要原始字符串,只需按这些数字排序即可.

I need the original strings, just ordered on those numbers.

基本上,您需要做的是将谓词传递给OrderBy,并按数字告诉它进行排序:

Basically what you need to do is to pass a predicate to the OrderBy and tell it to order by the number:

var items = strings.OrderBy(
   x => double.Parse( x.Substring( x.IndexOf( "(" ) + 1, 
   x.IndexOf( ")" ) - x.IndexOf( "(" ) - 1 ) ));


OO方法如何?

我们正在订购字符串,但是我们需要将它们像数字一样对待.如果有一种方法我们可以直接调用OrderBy并为我们进行排序,那不是很好吗?好吧. OrderBy方法将使用IComparable<T>(如果有的话).让我们创建一个类来保存jpg路径并实现IComparable<T>接口.

We are ordering string but we need to treat them like numbers. Wouldn't it be nice if there was a way we can just call OrderBy and it does the ordering for us? Well there is. The OrderBy method will use the IComparable<T> if there is one. Let's create a class to hold our jpg paths and implement the IComparable<T> interface.

public class CustomJpg : IComparable<CustomJpg>
{
    public CustomJpg(string path)
    {
        this.Path = path;
    }

    public string Path { get; private set; }

    private double number = -1;

    // You can even make this public if you want.
    private double Number
    {
        get
        {
            // Let's cache the number for subsequent calls
            if (this.number == -1)
            {
                int myStart = this.Path.IndexOf("(") + 1;
                int myEnd = this.Path.IndexOf(")");
                string myNumber = this.Path.Substring(myStart, myEnd - myStart);
                double myVal;
                if (double.TryParse(myNumber, out myVal))
                {
                    this.number = myVal;
                }
                else
                {
                    throw new ArgumentException(string.Format("{0} has no parenthesis or a number between parenthesis.", this.Path));
                }
            }

            return this.number;
        }
    }

    public int CompareTo(CustomJpg other)
    {
        if (other == null)
        {
            return 1;
        }

        return this.Number.CompareTo(other.Number);
    }
}

上述方法的好处是,如果我们继续调用OrderBy,则不必每次都搜索开头(和结尾)并进行数字解析.它将在第一次调用时对其进行缓存,然后继续使用它.另一个好处是,我们可以绑定到Path属性,也可以绑定到Number(我们必须将access修饰符从private更改).我们甚至可以引入一个新属性来保存缩略图并绑定到该缩略图.如您所见,这种方法更加灵活,干净和面向对象.再加上用于查找数字的代码在一个位置,因此,如果我们从()切换到另一个符号,我们将在一个位置进行更改.或者,我们可以进行修改以首先查找(),如果找不到,则查找另一个符号.

What is nice about the above approach is if we keep calling OrderBy, it will not have to search for the opening ( and ending ) and doing the parsing of the number every time. It caches it the first time it is called and then keeps using it. The other nice thing is that we can bind to the Path property and also to the Number (we would have to change the access modifier from private). We can even introduce a new property to hold the thumbnail image and bind to that as well. As you can see, this approach is far more flexible, clean and an OO approach. Plus the code for finding the number is in one place so if we switch from () to another symbol, we would just change it in one place. Or we can modify to look for () first and if not found look for another symbol.

这里是用法:

List<CustomJpg> jpgs = new List<CustomJpg>
{
    new CustomJpg("some-name-(1).jpg"),
    new CustomJpg("some-name-(5).jpg"),
    new CustomJpg("some-name-(5.1).jpg"),
    new CustomJpg("some-name-(6).jpg"),
    new CustomJpg("some-name-(12).jpg")
};

var ordered = jpgs.OrderBy(x => x).ToList();

您可以对任何对象使用此方法.

You can use this approach for any object.

这篇关于如何使用C#在数字子字符串上排序字符串列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆