Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/278.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#自定义列表排序_C#_List_Sorting - Fatal编程技术网

C#自定义列表排序

C#自定义列表排序,c#,list,sorting,C#,List,Sorting,我有一个程序,可以在目录中查找所有.csv报告文件。这些报告存储在一个列表中 List<string> _items = new List<string>(); List_items=newlist(); 这些报告的名称如下: “month year.csv”(示例:“Avgust 2010.csv) 我想把我的报告按月分类 月份的顺序如下: 1月、2月、马雷克、4月、maj、, junij,julij,avgust,9月, 奥克托伯,11月,12月 我该怎么做 Br

我有一个程序,可以在目录中查找所有.csv报告文件。这些报告存储在一个列表中

List<string> _items = new List<string>();
List_items=newlist();
这些报告的名称如下:

“month year.csv”(示例:“Avgust 2010.csv)

我想把我的报告按月分类

月份的顺序如下:

1月、2月、马雷克、4月、maj、, junij,julij,avgust,9月, 奥克托伯,11月,12月

我该怎么做


Br,Wolfy

听起来您应该编写一个方法,将文件名解析为
日期时间。例如,它可以去掉扩展名,用空格分割其余部分,然后将第二部分解析为年份,并在表中查找月份名称

一旦你有了这种方法,你就可以:

_items = _items.OrderBy(FilenameToDate).ToList();

最紧凑的完整解决方案如下:

CultureInfo sloveneCultureInfo = new CultureInfo("sl-SI");
_items = _items.OrderBy(fn => DateTime.ParseExact("01 " + fn, @"dd MMMM yyyy\.\c\s\v", sloveneCultureInfo)).ToList();
上面的命令将此列表重新分配给自身。如果您打算这样做,那么通过适当的排序,您可以在代码复杂度增加相对较少的情况下提高性能:

CultureInfo sloveneCultureInfo = new CultureInfo("sl-SI");
_items.Sort((x, y) => DateTime.ParseExact("01 " + x, @"dd MMMM yyyy\.\c\s\v",sloveneCultureInfo).CompareTo(DateTime.ParseExact("01 " + y, @"dd MMMM yyyy\.\c\s\v", sloveneCultureInfo)));
(如果您在斯洛文尼亚地区运行的系统上运行此功能,则可以使用
CurrentCulture
而不是上面构造的
sloveneCultureInfo

通过使用comparer类而不是lambda,可以进行进一步的改进,事实上,比较本身可能比上面提到的更有效,但我不会担心这一点,除非证明排序是一个瓶颈

编辑:这里的工作原理的分解

对列表进行排序有两种方便的方法(严格来说,一种是对列表进行排序,另一种是对任何IEnumerable或IQueryable进行排序)

OrderBy
接受一个计算排序键的参数,并返回一个
iorderenumerable
(或者
IOrderedQueryable
从现在起,我将忽略一个事实,即这也可以在
IQueryable
上完成,因为原理是相同的)。这个类在大多数情况下都像一个按键排序的
IEnumerable
,唯一的区别是,如果您在它上面执行后续的
ThenBy
,它将按第一个键排序,因此允许您进行多级排序

因此,在代码中:

var x = _items.OrderBy(SomeMethod);
SomeMethod
将返回可排序的值,在此基础上,x将被赋予一个相应排序的
IORDerenumerable
。例如,如果
SomeMethod
获取一个字符串并返回该字符串的长度,那么我们可以使用它按长度对字符串列表进行排序

如果我们要遍历_项,那么这就是我们的工作完成了。如果我们想要一个新的列表,那么我们可以对结果调用
Tolist()
,这将返回这样一个列表

另一种只对列表有效的方法是调用
Sort()
。有一个无参数表单,它只根据所讨论类型的默认比较(如果有)进行排序,一个表单采用
IComparer
对象(在大多数情况下涉及的内容比必要的多,但有时非常有用),一个表单采用委托或lambda(严格来说,它需要一个委托,但我们可以使用lambda来创建该委托)

此委托必须接收列表项类型的两个值,如果第一个值排序早于后一个值,则返回负数;如果它们相等,则返回零;否则返回正数

Sort()
更改列表的完成时间。这会提高效率,但如果您还需要保留原始排序顺序,则显然是灾难性的

好的,到目前为止,我们有两种方法对列表进行排序。这两种方法都需要将文件名转换为可以排序的内容

由于文件名与日期相关,并且日期已经可以排序,因此最明智的方法是获取这些日期

我们不能直接从文件名创建日期,因为Avgust 2010不是一个日期,只是一个月-年值,BCL中没有一个月-年类(可能在其他库中有,但我们不要镀金百合花)

但是,每个月都有第一天,因此我们可以从与文件名连接的“01”创建一个有效日期。因此,我们的第一步是说,我们将对
“01”+fn
采取行动,其中
fn
是文件名

这为我们提供了字符串的形式,例如
“01 Avgust 2010.csv”
。通过检查日期解析的工作原理,我们知道可以使用
dd
表示两位数的日期,
MMMM
表示相关语言中月份的全名(本例中为斯洛文尼亚语)和全年的
yyyy
。我们只需要添加
\.\c\s\v
,这意味着它后面会有一个我们不解析的“.csv”,我们已经设置好了。因此,我们可以将文件名转换为其月份的第一个日期时间。ParseExact(“01”+fn,@“dd MMMM yyyy\。\c\s\v”,新文化(“sl SI”))
其中fn是文件名。要使其成为lambda表达式,我们使用
fn=>DateTime.ParseExact(“01”+fn,@“dd-MMMM-yyyy\。\c\s\v”,新区域性(“sl-SI”)

第一种方法现在已经完成,我们调用
\u items.OrderBy(fn=>DateTime.ParseExact(“01”+fn,@“dd-MMMM-yyyy\。\c\s\v”,新区域性(“sl-SI”))
,并且依赖于
OrderBy
知道如何排序
DateTime

对于第二种方法,我们需要获取两个值并自己进行比较。我们可以通过调用
ParseExact
返回的
DateTime
上的
CompareTo()
来实现这一点


最后,我们将
CultureInfo
结构移出,以初始化名为
sloveneCultureInfo
的变量,以避免对基本相同对象的多个创建进行浪费性调用。

@generic否,这是正确的。目的是将委托传递到OrderBy,以便在排序过程中调用它,而不是将其称为传递OrderBy的未定义结果