简体   繁体   English

c#csv使用第三列排序列表

[英]c# csv sorting a list using third columns

I have a program that opens a CSV file using StreamReader and creates a table with 4 columns and rows for however many rows are in the CSV file. 我有一个程序,使用StreamReader打开CSV文件,并创建一个包含4列和行的表,但CSV文件中有很多行。 This works correctly as is creating the output of: 这可以正常创建输出:

Item Code, Item Description, Current Count, On Order 物料代码,物料描述,当前计数,订单

A0001, Toy Car, 4, Yes A0001,玩具车,4,是的

A0002, Toy Truck, 1, No A0002,玩具卡车,1,没有

I save all the data from the CSV file in a global list without splitting each line. 我将CSV文件中的所有数据保存在全局列表中,而不分割每一行。 When I am creating the table I split the lines using "Split(',')", which works as needed at the time. 当我创建表格时,我使用“Split(',')”分割线条,当时根据需要使用。 However I am unsure how to reorder the whole list using the Current Count column from largest to smallest. 但是,我不确定如何使用“当前计数”列从最大到最小重新排序整个列表。 I have tried the following but it give an error on the Split(','). 我尝试了以下但它在Split(',')上给出了错误。

public static class Globals
{
    public static List<string> items = new List<string>();
}
private void createTableWithOrder(int order)
{
    for (int i = 0; i < Globals.items.; i++)
    {
         var values = Globals.items[i].Split(',');

         if (order == 1)
         {
              values = Globals.items[i].OrderBy(itemDesc => itemDesc.Split(',')).ToList();
         }
    }
}

The Error given is below: 给出的错误如下:

'char' does not contain a definition for 'Split' and no extension method 'Split' accepting a first argument of type 'char' could be found (are you missing a using directive or an assembly reference?) 'char'不包含'Split'的定义,并且没有扩展方法'Split'可以找到接受'char'类型的第一个参数(你是否缺少using指令或汇编引用?)

The OrderBy call is working on all characters in the string at Globals.items[i] . OrderBy调用正在处理Globals.items[i]字符串中的所有字符 That is why you're seeing the current error. 这就是你看到当前错误的原因。 In order to sort the entire collection the order by needs to be made on the list as a whole, eg: 为了对整个集合进行排序,需要在整个列表中进行排序,例如:

var values = Globals.items.Select(line => line.Split(',')); // Select columns for all rows
var orderedListOfValues = values
    .OrderByDescending(cols => int.TryParse(cols[2].Trim(), out var order) ? order : int.MaxValue); // Sort  by count as an integer

Note that in the above example sorting on non-numeric values (eg heading) will use the maximum value of an integer. 请注意,在上面的示例中,对非数字值(例如,标题)进行排序将使用整数的最大值。 Depending on the expected outcome, these results can then be merged back into a list of strings for presentation: 根据预期的结果,这些结果可以合并回一个字符串列表以供呈现:

var orderedItems = string.Join(",", orderedListOfValues)

Cheers! 干杯!

The way you have stored the list will not help you to generate a table with sorting capability. 存储列表的方式无法帮助您生成具有排序功能的表。 To solve your problem instead of List<string> you should create a model(IItem interface and Item class) using those models create List. 要解决您的问题而不是List<string>您应该使用这些模型创建List来创建模型(IItem接口和Item类)。 Then before rendering the table you can sort the List on whatever column you like. 然后在渲染表之前,您可以在您喜欢的任何列上对List进行排序。

List<IItem> items = new List<Item>();
items.Add({itemCode: excelData.itemCode , itemDescription: excelData.itemDescription,itemCount: excelData.itemCount, orderCount:excelData.orderCount});
List<IItem> itemsToCreateTable = items.OrderBy(o=>o.itemCount).ToList();

It is no clear why you would not simply make a “Class” of the items in the file. 不清楚为什么你不会简单地在文件中创建项目的“类”。 With a “Class” you can sort the items any way you choose and in numerous ways. 使用“类”,您可以通过多种方式对项目进行排序。 In addition, it appears the column you want to sort by (Current Count) is a NUMBER. 此外,您要排序的列(当前计数)似乎是一个数字。 If you sort numbers as strings , you will get all the 1's together, 2's together etc. Example it would look something like. 如果你将数字排序为strings ,你将把所有的1组合在一起,2组合在一起等等。例如它看起来像。

1 1

10 10

100 100

2 2

20 20

3 3

4 … 4 ...

You will not get the proper NUMERICAL sort order using strings. 您不会使用字符串获得正确的NUMERICAL排序顺序。 Therefore, you must sort the column by the number and not the string to get the correct numerical order. 因此,您必须按数字而不是字符串对列进行排序,以获得正确的数字顺序。 The idea behind using a class is it gives you full control over the sorting. 使用类的想法是它让您完全控制排序。 If you make a List of Item and the Item class implements the IComparable interface, the sorting could be done with one line of code… Items.Sort(). 如果你犯了一个ListItemItem类实现IComparable接口,排序可以用一行代码...来完成Items.Sort().

Below is an example of what is described above. 以下是上述内容的示例。 First the “Class” Item to hold the objects in the file. 首先是“类” Item用于保存文件中的对象。 It contains only the properties need for this example, namely the CompareTo method which will get used when you call Items.Sort(). 它仅包含此示例所需的属性,即在调用Items.Sort().时将使用的CompareTo方法Items.Sort().

public class Item : IComparable {

  public string Code { get; set; }
  public string Description { get; set; }
  public int Count { get; set; }
  public bool OnOrder { get; set; }

  public Item(string code, string description, int count, bool onOrder) {
    Code = code;
    Description = description;
    Count = count;
    OnOrder = onOrder;
  }

  public int CompareTo(object obj) {
    Item that = (Item)obj;
    return Count.CompareTo(that.Count);
  } 
}

Below is an example of using the Item class to SORT the list by the “Current Count” column. 下面是使用Item类按“当前计数”列对列表进行排序的示例。 A DataGridView is used to display the sorted list. DataGridView用于显示排序列表。

List<Item> Items;

public Form1() {
  InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e) {
  Items = GetData();
  Items.Sort();
  dataGridView1.DataSource = Items;
}

private List<Item> GetData() {
  List<Item> items = new List<Item>();
  Item newItem;
  string line;
  using (StreamReader sr = new StreamReader(@"D:\Test\Test22.csv")) {
    while ((line = sr.ReadLine()) != null) {
      if ((newItem = GetItemFromString(line)) != null) {
        items.Add(newItem);
      }
    }
  }
  return items;
}

private Item GetItemFromString(string itemString) {
  string[] splitArray = itemString.Split(',');
  bool onOrder;
  int count = 0;
  if (splitArray.Length >= 4) {
    int.TryParse(splitArray[2].Trim(), out count);
    if (splitArray[3].Trim() == "Yes")
      onOrder = true;
    else
      onOrder = false;
    return new Item(splitArray[0].Trim(), splitArray[1].Trim(), count, onOrder);
  }
  return null;
}

Hope this helps. 希望这可以帮助。

Not a direct answer to your question. 不能直接回答你的问题。 But I think you are writing code that is already available for free. 但我认为您正在编写已经免费提供的代码。

I strongly suggest that you use nuget package CSV Helper . 我强烈建议你使用nuget包CSV Helper It takes any text stream, string, text reader etc, and converts the CSV file into an IEnumerable of the type that you expect. 它需要任何文本流,字符串,文本阅读器等,并将CSV文件转换为您期望的类型的IEnumerable。 It works with and without a header line containing the columns 它可以使用和不使用包含列的标题行

class MyItem
{
    public string Code {get; set;}
    public string Description {get; set;}
    public int Count {get; set;}
    public bool OnOrder {get; set;}
}

Getting all MyItems from the CSV file: 从CSV文件中获取所有MyItems:

string myCsvFileName = ...
using (TextReader reader = new StreamReader(myCsvFileName))
{
    using (var csv = new CsvReader(reader))
    {    
        IEnumerable<MyItem> items = reader.GetRecords<MyItem>();

        // you can do any Linq with this:
        var allItems = items.ToList();

        // or if you only need some records:
        var unAvailableItems = items.Where(item => item.Count == 0);
    }
}

Read the link to see what to do if you have a special separator, a header line, or anything else. 阅读链接,了解如果您有特殊的分隔符,标题行或其他任何内容,该怎么做。 It is highly configurable. 它具有高度可配置性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM