如何使用 C# 对数字子字符串上的字符串列表进行排序
How to order list of strings on number substring using C#
我有一个字符串列表,每个字符串都包含一个数字子字符串,我想根据该子字符串的数值对其进行重新排序。该集合看起来像这样,但更大:
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
是靠谱的。请注意,不仅可能缺少数字,还可能存在小数,而不仅仅是整数。
我很难得到一个重新排序的列表,其中包含那些已根据该子字符串的数值排序的相同字符串。有没有人有办法做到这一点,希望表现良好?谢谢
这将检查括号之间的项目是否可转换为 double
,如果不是,则在这种情况下将 return -1。
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
如果您确定括号之间总会有一个数字,则使用它,因为它更短:
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
并告诉它按数字排序:
var items = strings.OrderBy(
x => double.Parse( x.Substring( x.IndexOf( "(" ) + 1,
x.IndexOf( ")" ) - x.IndexOf( "(" ) - 1 ) ));
OO 方法如何?
我们正在订购字符串,但我们需要像对待数字一样对待它们。如果有一种方法我们可以调用 OrderBy
并由它为我们排序,那不是很好吗?嗯,有。 OrderBy
方法将使用 IComparable<T>
(如果有的话)。让我们创建一个 class 来保存我们的 jpg 路径并实现 IComparable<T>
接口。
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
(我们必须将访问修饰符从私有更改)。我们甚至可以引入一个新的 属性 来保存缩略图并绑定到它。如您所见,这种方法更加灵活、简洁并且是一种 OO 方法。另外,查找数字的代码在一个地方,所以如果我们从 ()
切换到另一个符号,我们只需在一个地方更改它。或者我们可以修改为先查找 ()
,如果找不到则查找另一个符号。
用法如下:
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();
您可以对任何对象使用这种方法。
如果您先切掉从右括号 ")"
开始的部分,您可以使子串选择更容易。也就是说,从 "some-name-(5.1).jpg"
你首先得到 "some-name-(5.1"
。然后接"("
之后的部分。这节省了长度计算,因为第二个 Substring
自动将所有内容都带到字符串的末尾。
strings = strings
.OrderBy(x => Decimal.Parse(
x.Substring(0, x.IndexOf(")"))
.Substring(x.IndexOf("(") + 1)
)
)
.ToList();
这在这里可能不是很重要,但一般来说,decimal
比 double
更准确地存储以十进制表示法给出的数字。 double
可以将 17.2
转换为 17.19999999999999
.
在上面的示例代码中 return 一个按数字排序的数字列表,但是如果你想要更好地按名称排序的文件名列表,你可以在数字的开头输入相同的零,例如 "some-name-(001).jpg" 你可以简单地
命令
List<string> strings = new List<string>
{
"some-name-(001).jpg",
"some-name-(005.1).jpg",
"some-name-(005).jpg",
"some-name-(004).jpg",
"some-name-(006).jpg",
"some-name-(012).jpg"
};
var orederedByName =strings.Select(s =>s ).OrderBy(s=>s);
我有一个字符串列表,每个字符串都包含一个数字子字符串,我想根据该子字符串的数值对其进行重新排序。该集合看起来像这样,但更大:
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
是靠谱的。请注意,不仅可能缺少数字,还可能存在小数,而不仅仅是整数。
我很难得到一个重新排序的列表,其中包含那些已根据该子字符串的数值排序的相同字符串。有没有人有办法做到这一点,希望表现良好?谢谢
这将检查括号之间的项目是否可转换为 double
,如果不是,则在这种情况下将 return -1。
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
如果您确定括号之间总会有一个数字,则使用它,因为它更短:
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
并告诉它按数字排序:
var items = strings.OrderBy(
x => double.Parse( x.Substring( x.IndexOf( "(" ) + 1,
x.IndexOf( ")" ) - x.IndexOf( "(" ) - 1 ) ));
OO 方法如何?
我们正在订购字符串,但我们需要像对待数字一样对待它们。如果有一种方法我们可以调用 OrderBy
并由它为我们排序,那不是很好吗?嗯,有。 OrderBy
方法将使用 IComparable<T>
(如果有的话)。让我们创建一个 class 来保存我们的 jpg 路径并实现 IComparable<T>
接口。
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
(我们必须将访问修饰符从私有更改)。我们甚至可以引入一个新的 属性 来保存缩略图并绑定到它。如您所见,这种方法更加灵活、简洁并且是一种 OO 方法。另外,查找数字的代码在一个地方,所以如果我们从 ()
切换到另一个符号,我们只需在一个地方更改它。或者我们可以修改为先查找 ()
,如果找不到则查找另一个符号。
用法如下:
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();
您可以对任何对象使用这种方法。
如果您先切掉从右括号 ")"
开始的部分,您可以使子串选择更容易。也就是说,从 "some-name-(5.1).jpg"
你首先得到 "some-name-(5.1"
。然后接"("
之后的部分。这节省了长度计算,因为第二个 Substring
自动将所有内容都带到字符串的末尾。
strings = strings
.OrderBy(x => Decimal.Parse(
x.Substring(0, x.IndexOf(")"))
.Substring(x.IndexOf("(") + 1)
)
)
.ToList();
这在这里可能不是很重要,但一般来说,decimal
比 double
更准确地存储以十进制表示法给出的数字。 double
可以将 17.2
转换为 17.19999999999999
.
在上面的示例代码中 return 一个按数字排序的数字列表,但是如果你想要更好地按名称排序的文件名列表,你可以在数字的开头输入相同的零,例如 "some-name-(001).jpg" 你可以简单地 命令
List<string> strings = new List<string>
{
"some-name-(001).jpg",
"some-name-(005.1).jpg",
"some-name-(005).jpg",
"some-name-(004).jpg",
"some-name-(006).jpg",
"some-name-(012).jpg"
};
var orederedByName =strings.Select(s =>s ).OrderBy(s=>s);