假设我有一个如下的CSV文件:
```
Column1,Column2,Column3
C,3,1
B,2,2
A,3,3
C,3,10
B,2,20
A,2,30
C,3,100
B,1,200
A,1,300
```
我想按照以下顺序对其进行排序:
1. 首先按Column1排序
2. 其次按Column2排序
3. 最后按Column3排序
排序后的结果应该是这样的:
```
Column1,Column2,Column3
A,1,300
A,2,30
A,3,3
B,1,200
B,2,2
B,2,20
C,3,1
C,3,10
C,3,100
```
为了按列对CSV进行升序/降序排序,我创建了以下类:
```csharp
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace SikorskiLibMemoryLess
{
public enum SortTypeEnum
{
Ascending,
Descending
}
public static class ListExtensions
{
public static string ToCommaSeparatedString(this List list)
{
if (list == null || !list.Any())
{
return string.Empty;
}
return string.Join(",", list);
}
}
public class CSVSorter
{
public List Header { get; private set; }
public List
- > Data { get; private set; }
public CSVSorter()
{
Data = new List
- >();
}
public void LoadCSV(string filePath, bool hasHeader = true)
{
using (StreamReader sr = new StreamReader(filePath))
{
string line;
bool isFirstLine = true;
while ((line = sr.ReadLine()) != null)
{
List
- > csvData, bool hasHeader = true)
{
bool isFirstLine = true;
foreach (var columns in csvData)
{
var processedColumns = columns.Select(col => string.IsNullOrWhiteSpace(col) ? null : col).ToList();
if (isFirstLine && hasHeader)
{
Header = processedColumns;
isFirstLine = false;
}
else
{
Data.Add(processedColumns);
if (isFirstLine)
{
isFirstLine = false;
if (!hasHeader)
{
Header = Enumerable.Range(1, processedColumns.Count).Select(i => "Column" + i).ToList();
}
}
}
}
}
public void Sort(int[] columns, SortTypeEnum ascendingOrDescending)
{
try
{
IOrderedEnumerable
- > sortedData = null;
if (ascendingOrDescending == SortTypeEnum.Ascending)
{
sortedData = Data.OrderBy(row => GetColumnValueSafe(row, columns[0]));
for (int i = 1; i < columns.Length; i++)
{
sortedData = sortedData.ThenBy(row => GetColumnValueSafe(row, columns[i]));
}
}
Data = sortedData.ToList();
}
catch (Exception ex)
{
Console.WriteLine($"Error during sorting: {ex.Message}");
Console.WriteLine(ex.StackTrace);
}
}
private string GetColumnValueSafe(List
- > Get()
{
yield return Header;
foreach (var row in Data)
{
yield return row;
}
}
public void SaveCSV(string filePath)
{
using (StreamWriter sw = new StreamWriter(filePath))
{
// 写入标题
sw.WriteLine(string.Join(",", Header));
// 写入数据行
foreach (var row in Data)
{
sw.WriteLine(string.Join(",", row.Select(col => col ?? "")));
}
}
}
public void SaveCSV(string fileName, string fileDir)
{
string
在您的示例代码中,您没有使用期望的参数
new int[]{0, 1, 2}
(编辑:现在您在问题中已经修正了它),因为您想要首先按第一列排序,然后按其他列排序。如果您这样做,您将得到一个IndexOutOfRangeException
(在您的 catch 中)。这是因为您的循环中有一个微妙的错误:Resharper 会在这里告诉您:“捕获的变量在外层作用域中被修改”,这就是导致问题的原因。所以修复方法很简单,创建该变量的副本;
另一个 - 更好的 - 选择是使用
foreach
(C#5 已经修正了它):有关更多详细信息,请参阅此答案:C# 在 foreach 中重用变量有什么原因吗?
现在您得到了期望的结果,因为其他部分似乎都正常工作: