我必须在csv文件中对多个列进行排序。 我文件的一部分是这样的:
Number | Section | Color | Length | Panel1 | Panel2 | Description
1 1.5 BK 200 PAN5A PAN5B ABC
2 0.75 BK 620 PAN3A PAN3A ACC
3 2 RD 150 PAN2A PAN2A AAA
4 1.5 BL 500 PAN2A PAN2A ABB
5 0.75 GY 250 PAN1A PAN2A AAA
6 5.25 GY 200 PAN3A PAN3B CCC
7 1.25 BU 150 PAN4A PAN4A DDD
8 0.75 BK 800 PAN4A PAN4A BBB
我必须按特定顺序订购第3列(颜色)。我必须遵循的顺序是以下(GY,BL,RD,其他颜色,BK),是颜色的首字母缩略词。 然后我必须按编号对第2列(部分)进行订购,第4列(长度)也按编号订购。
目标是拥有以下csv文件。
Number | Section | Color | Length | Panel1 | Panel2 | Description
5 0.75 GY 250 PAN1A PAN2A AAA
6 5.25 GY 200 PAN3A PAN3B CCC
4 1.5 BL 500 PAN2A PAN2A ABB
3 2 RD 150 PAN2A PAN2A AAA
7 1.25 BU 150 PAN4A PAN4A DDD`
2 0.75 BK 620 PAN3A PAN3A ACC
8 0.75 BK 800 PAN4A PAN4A BBB
1 1.5 BK 200 PAN5A PAN5B ABC
下面我放了我的代码,但它有问题。由于第3列按字母顺序排序,因此第2列和第4列将数字视为字符串,因此不遵循正确的顺序。
var sorted = File.ReadLines(pathFile)
.Select(line => new
{
SortKeyColor = line.Split(';')[2],
SortKeySection = line.Split(';')[1],
SortKeyLenght = line.Split(';')[3],
Line = line
})
.OrderBy(x => x.SortKeyColor)
.ThenBy(x => x.SortKeySection)
.ThenBy(x => x.SortKeyLenght)
.Select(x => x.Line);
File.WriteAllLines(pathNewFile, sorted);
我也试过把Int32.Parse但我得到异常“输入字符串格式不正确。”
SortKeySection = Int32.Parse(line.Split(';')[1]),
答案 0 :(得分:0)
您会收到格式异常,因为第1列(实际上是第二列)不是整数。这应该有效:
.ThenBy(x => double.Parse(x.SortKeySection))
.ThenBy(x => int.Parse(x.SortKeyLenght))
但调整SortKeySection
和SortKeyLength
的类型并分配正确的数据类型会更好(也更快):
SortKeySection = double.Parse(line.Split(';')[1]),
SortKeyLenght = int.Parse(line.Split(';')[3]),
根据您的语言环境,您可能希望添加特定的文化,例如:
double.Parse(line.Split(';')[1], CultureInfo.InvariantCulture)
如果您的本地数字格式具有不同的小数点分隔符,例如,
或;
。
对于颜色的正确顺序,您可能希望使用自定义IComparer<string>
,以便更好地控制哪个元素应该先于另一个元素。例如,此实现首先对GY
,BL
和RD
进行排序,然后按字母顺序对所有其他内容进行排序,然后对所有BK
进行排序:
public class ColorNameComparer : IComparer<string>
{
private readonly List<string> colorOrder = new List<string>{"GY", "BL", "RD"};
public int Compare(string x, string y)
{
if (x == y) return 0;
if (x == "BK") return 1;
if (y == "BK") return -1;
if (colorOrder.Contains(x) && colorOrder.Contains(y))
return colorOrder.IndexOf(x) > colorOrder.IndexOf(y) ? 1 : -1;
if (colorOrder.Contains(x))
return -1;
if (colorOrder.Contains(y))
return 1;
return String.Compare(x, y, StringComparison.Ordinal);
}
}
可以像这样使用:
.OrderBy(x => x.SortKeyColor, new ColorNameComparer())
using System;
using System.Linq;
using System.Collections.Generic;
using System.Globalization;
namespace ConsoleApp
{
public class Program
{
public static void Main()
{
string file =
"1;1.5;BK;200;PAN5A;PAN5B;ABC\r\n" +
"2;0.75;BK;620;PAN3A;PAN3A;ACC\r\n" +
"3;2;RD;150;PAN2A;PAN2A;AAA\r\n" +
"4;1.5;BL;500;PAN2A;PAN2A;ABB\r\n" +
"5;0.75;GY;250;PAN1A;PAN2A;AAA\r\n" +
"6;5.25;GY;200;PAN3A;PAN3B;CCC\r\n" +
"7;1.25;BU;150;PAN4A;PAN4A;DDD\r\n" +
"8;0.75;BK;800;PAN4A;PAN4A;BBB";
string[] lines = file.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
var sorted = lines.Select(line => new
{
SortKeyColor = line.Split(';')[2],
SortKeySection = double.Parse(line.Split(';')[1], CultureInfo.InvariantCulture),
SortKeyLenght = int.Parse(line.Split(';')[3]),
Line = line
}
).OrderBy(x => x.SortKeyColor, new ColorNameComparer()).ThenBy(x => x.SortKeySection).ThenBy(x => x.SortKeyLenght).Select(x => x.Line);
foreach (var entry in sorted)
Console.WriteLine(entry);
}
}
public class ColorNameComparer : IComparer<string>
{
private readonly List<string> colorOrder = new List<string> {"GY", "BL", "RD"};
public int Compare(string x, string y)
{
if (x == y)
return 0;
if (x == "BK")
return 1;
if (y == "BK")
return -1;
if (colorOrder.Contains(x) && colorOrder.Contains(y))
return colorOrder.IndexOf(x) > colorOrder.IndexOf(y) ? 1 : -1;
if (colorOrder.Contains(x))
return -1;
if (colorOrder.Contains(y))
return 1;
return String.Compare(x, y, StringComparison.Ordinal);
}
}
}
答案 1 :(得分:0)
您可以使用临时int值替换“SortKeyColor”的值进行排序:
// Converting string to integers with the desired order
Func<string, int> converter = (color) =>
{
switch (color)
{
case "GY": return 0;
case "BL": return 1;
case "RD": return 2;
case "BK": return 4;
default: return 3;
}
};
var sorted = File.ReadLines("")
.Select(line => new
{
SortKeyColor = converter(line.Split(';')[2]),
SortKeySection = double.Parse(line.Split(';')[1]),
SortKeyLenght = int.Parse(line.Split(';')[3]),
Line = line
})
.OrderBy(x => x.SortKeyColor)
.ThenBy(x => x.SortKeySection)
.ThenBy(x => x.SortKeyLenght)
.Select(x => x.Line);
编辑:我添加了转换方法。
答案 2 :(得分:0)
尝试实现自定义比较器
public class CustomComparer : IComparer<string>
{
Dictionary<string, int> colorPriorities;
public CustomComparer()
{
colorPriorities = new Dictionary<string, int>();
colorPriorities.Add("GY", 1);
colorPriorities.Add("BL", 2);
colorPriorities.Add("RD", 4);
colorPriorities.Add("BK", 8);
}
public int GetPriority(string color)
{
if (!colorPriorities.ContainsKey(color))
{
return 5;
}
return colorPriorities[color];
}
public int Compare(string x, string y)
{
string xSortKeyColor = x.Split(';')[2];
double xSortKeySection = Convert.ToDouble(x.Split(';')[1]);
double xSortKeyLenght = Convert.ToDouble(x.Split(';')[3]);
string ySortKeyColor = y.Split(';')[2];
double ySortKeySection = Convert.ToDouble(y.Split(';')[1]);
double ySortKeyLenght = Convert.ToDouble(y.Split(';')[3]);
if (xSortKeyColor != ySortKeyColor)
return GetPriority(xSortKeyColor).CompareTo(GetPriority(ySortKeyColor));
if (xSortKeySection != ySortKeySection)
return xSortKeySection.CompareTo(ySortKeySection);
return xSortKeyLenght.CompareTo(ySortKeyLenght);
}
}