我有一个字符串列表。每个字符串都遵循“{Path} \ UpdateTo {Version} - {Order}”模式。
我需要对列表进行排序,使最低版本号位于顶部。如果存在多个具有相同版本号的文件,则会附加可选的订单参数。如果任何字符串上存在订单,那么它应该出现在具有相同版本号且没有订单号的字符串上方。
例如,给出以下列表(注意项目是随机排序的):
var files = new List<string>() {
@"C:\Migrations\UpdateTo1.2-2",
@"C:\Migrations\UpdateTo1.5-2",
@"C:\Migrations\UpdateTo1.2",
@"C:\Migrations\UpdateTo1.4",
@"C:\Migrations\UpdateTo1.1",
@"C:\Migrations\UpdateTo1.5",
@"C:\Migrations\UpdateTo1.2-1",
@"C:\Migrations\UpdateTo1.5-1"
};
结果将是:
var files = new List<string>() {
@"C:\Migrations\UpdateTo1.1",
@"C:\Migrations\UpdateTo1.2-1",
@"C:\Migrations\UpdateTo1.2-2",
@"C:\Migrations\UpdateTo1.2",
@"C:\Migrations\UpdateTo1.4",
@"C:\Migrations\UpdateTo1.5-1",
@"C:\Migrations\UpdateTo1.5-2",
@"C:\Migrations\UpdateTo1.5"
}
我一直在尝试各种各样的想法,但到目前为止,我的尝试一直是一团糟。如果有人可以提供帮助,我会很感激。感谢
答案 0 :(得分:5)
我使用临时类来处理解析和比较以获得所需的输出。我已经包含了一些代码,可以将所有内容恢复到您的请求,但引入的“临时”类可能对路径(?)有更多的价值。
用法:
var sorted = files.Select(f => new UpdateTo(f))
.OrderBy(u => u)
.Select(u => u.Path)
.ToArray();
代码:
class UpdateTo : IComparable<UpdateTo>
{
public decimal Version { get; private set; }
public int Order { get; private set; }
public string Path { get; private set; }
private const string Prefix = "UpdateTo";
public UpdateTo(string path)
{
/* No error-checking here -- BEWARE!! */
Path = path;
string toParse = Path.Substring(Path.IndexOf(Prefix, StringComparison.InvariantCultureIgnoreCase) + Prefix.Length);
var split = toParse.Split('-');
Version = decimal.Parse(split[0]);
Order = split.Length == 2 ? int.Parse(split[1]) : int.MaxValue;
}
public int CompareTo(UpdateTo other)
{
int versionCompare = Version.CompareTo(other.Version);
return versionCompare == 0 ? Order.CompareTo(other.Order) : versionCompare;
}
}
测试......
[Test]
public void ListSort()
{
const string first = @"C:\Migrations\UpdateTo1.1";
const string second = @"C:\Migrations\UpdateTo1.2-1";
const string third = @"C:\Migrations\UpdateTo1.2-2";
const string fourth = @"C:\Migrations\UpdateTo1.2";
const string fifth = @"C:\Migrations\UpdateTo1.4";
const string sixth = @"C:\Migrations\UpdateTo1.5-1";
const string seventh = @"C:\Migrations\UpdateTo1.5-2";
const string eighth = @"C:\Migrations\UpdateTo1.5";
var files = new List<string>{third, seventh, fourth, fifth, first, eighth, second, sixth};
var sorted = files.Select(f => new UpdateTo(f))
.OrderBy(u => u)
.Select(u => u.Path)
.ToArray();
Assert.AreEqual(first, sorted[0]);
Assert.AreEqual(second, sorted[1]);
Assert.AreEqual(third, sorted[2]);
Assert.AreEqual(fourth, sorted[3]);
Assert.AreEqual(fifth, sorted[4]);
Assert.AreEqual(sixth, sorted[5]);
Assert.AreEqual(seventh, sorted[6]);
Assert.AreEqual(eighth, sorted[7]);
}
答案 1 :(得分:3)
files.Sort(delegate(string str1, string str2)
{
var pattern = @"(?<version>\d.*?$)";
var version1 = System.Text.RegularExpressions.Regex.Match(str1, pattern).Groups["version"].Value;
var version2 = System.Text.RegularExpressions.Regex.Match(str2, pattern).Groups["version"].Value;
// TODO: Implement your version comparison logic here
return string.Compare(version1, version2);
});
<强>更新强>
示例比较逻辑implementation将是:
files.Sort(delegate(string str1, string str2)
{
var pattern = @"(?<version>\d.*?$)";
var version1 = System.Text.RegularExpressions.Regex.Match(str1, pattern).Groups["version"].Value;
var version2 = System.Text.RegularExpressions.Regex.Match(str2, pattern).Groups["version"].Value;
if (version1 == version2) return 0;
// version1 != version2
var major1 = float.Parse(version1.Split('-')[0]);
var major2 = float.Parse(version2.Split('-')[0]);
if (major1 > major2) return 1; // version1 > version2
if (major1 < major2) return -1; // version1 < version2
// major1 = major2
if (version1.Split('-').Length > version2.Split('-').Length) return -1;
if (version1.Split('-').Length < version2.Split('-').Length) return 1;
var minor1 = float.Parse(version1.Split('-')[1]);
var minor2 = float.Parse(version2.Split('-')[1]);
return Comparer<float>.Default.Compare(minor1, minor2);
});
答案 2 :(得分:1)
您可以尝试以下方法:
// Warning! To keep this code clean I
// left out all error handling. Use at own risk.
//
// requires using System.Linq;
private int VersionSortingValue(string s)
{
int res = 0;
string[] items = s.Split('.', '-');
if(items.Length != 3)
{
res = 1;
}
return (int.Parse(items[0]) << 1) + res;
}
// actual sorting:
var prefix = "UpdateTo";
Func<string, string> getVersion =
x => x.Substring(x.LastIndexOf(prefix) + prefix.Length);
files = files
.OrderBy(x => VersionSortingValue(getVersion(x))
.ThenBy(x => getVersion(x))
.ToList();
如果版本号变大,您应该考虑使用natural sort。
答案 3 :(得分:1)
这是使用LINQ的另一个(有点terser,但可能不太可读)版本:
int prefixLength = "UpdateTo".Length;
var sorted = from file in files
let fileName = System.IO.Path.GetFileName(file)
let versionString = fileName.Substring(prefixLength, fileName.Length - prefixLength).Replace('-', '.')
let version = new Version(versionString)
orderby version
select file;
更新的 下面的改进版本考虑了订单价值的特殊情况:
var sorted = from file in files
let fileName = System.IO.Path.GetFileName(file)
let versionString = fileName.Substring(prefixLength, fileName.Length - prefixLength).Replace('-', '.')
let modified = versionString.IndexOf('.') == versionString.LastIndexOf('.') ? versionString + "." + Int32.MaxValue.ToString() : versionString
let version = new Version(modified)
orderby version
select file;