【问题标题】:tricky CSV file output based on a List<Order> orders collection基于 List<Order> 订单集合的棘手 CSV 文件输出
【发布时间】:2009-12-30 01:45:06
【问题描述】:

我必须制作这个 CSV 布局,但有点不确定如何去做。

我有一个 Order 类,我必须将其转换为 CSV 文件。

public class Order
{
       public int ID {get; set;}
       public int Created {get;set;}
       public List<Item> Items {get;set;}
}
public class Item
{
        public string Sku {get;set;}
        public int Quantity {get;set;}
}

所以每一行代表一个订单。如果订单中包含超过 2 个项目,我将不得不继续到下一行,将所有内容留空,除了 sku、数量和特定字段。

如果从上一行继续,最后一个字段将为“Y”,否则为“N”。

所以我有:

List<Order> orders = Db.GetOrders();

因此,CSV 的示例输出将是:

"orderID", "Created", "Item01", "quantity01", "Item02", "N"

如果超过2个,就必须输出:

"orderID", "Created", "Item01", "quantity01", "Item02", "N"
"", "", "Item03", "quantity03", "", "", "Y"

所以上面的订单有 3 个项目,请注意 Item#4 的占位符仍然存在,但只是空的双引号。

所以每个字段都是必填的。

我将如何制作这个?

到目前为止,我有:

StringBuilder sb = new StringBuilder();

for(int x = 0; x < orders.Count; x++)
{
         Order o = orders[x];

         if(x % 2 = 0)
         {
           sb.Append(o.ID).Append(",");
           sb.Append(o.Created).Append(",");
         }

}

我想的诀窍是弄清楚我是否需​​要继续下一行,然后如果我的行中少于 2 个项目,我必须填补任何空白位置? p>

(您可以忽略输出中的任何错误字符,我稍后会处理,谢谢)

【问题讨论】:

  • 吃mor chikin。接受早上的回答。

标签: c# csv


【解决方案1】:

我发现将此类问题分解为几种方法很有帮助,每种方法都易于理解并只完成一小部分工作。然后你可以将它们结合起来解决更大的问题。

以下内容可帮助您入门。它需要更多的错误处理,并且可能需要在生成 CSV 字段时处理转义特殊字符的逻辑(例如,如果 SKU 中可能包含逗号或引号)。

    public class Order
    {
        public int ID { get; set; }
        public int Created { get; set; }
        public List<Item> Items { get; set; }
    }
    public class Item
    {
        public string Sku { get; set; }
        public int Quantity { get; set; }
    }

    public class OrderCsvBuilder
    {
        private readonly StringBuilder m_CsvData = new StringBuilder();

        // constructor accepts a sequence or Orders
        public OrderCsvBuilder(IEnumerable<Order> orders)
        {
            foreach (var order in orders)
                WriteOrder(order);
        }

        // returns the formatted CSV data as a string
        public string GetCsvData()
        {
            return m_CsvData.ToString();
        }

        // writes a single order and its line items to csv format
        private void WriteOrder( Order order )
        {
            WriteCsvFields( false, order.ID, order.Created );
            var itemIndex = 0;
            foreach( var item in order.Items )
                WriteOrderItem( item, itemIndex++ );
        }

        // writes a single order item to csv format
        private void WriteOrderItem( Item item, int itemIndex )
        {
            // write the extra fields when the order item is not the first item
            if( itemIndex > 0 )
                WriteCsvFields( false, string.Empty, string.Empty );
            // use (?:) to append indicator of whether item is first or additional
            WriteCsvFields( true, item.Quantity, item.Sku, itemIndex > 0 ? "Y" : "N" );
        }

        // writes a series of fields to the file in csv form
        private void WriteCsvFields( bool isLineEnd, params object[] fields )
        {
            // write each field to the StringBuilder in CSV format
            // TODO: Need better error handling and escaping of special characters
            foreach( var field in fields )
            {
                m_CsvData.AppendFormat("\"{0}\", ", field);
            }
            // trim extra trailing space and comma if this is the last item of a line
            if( isLineEnd )
                m_CsvData.Remove(m_CsvData.Length - 2, 2);
        }
    }

【讨论】:

    【解决方案2】:
    public string BuildOrdersCsv(List<Order> orders)
    {
        StringBuilder sb = new StringBuilder();
    
        foreach (Order o in orders)
        {
            Append(sb, o.ID, o.Created);
            for (int i = 0; i < 2; i++)
            {
                if (i < o.Items.Count)
                    Append(sb, o.Items[i].Sku, o.Items[i].Quantity);
                else
                    Append(sb, "", "");
            }
            sb.AppendLine("\"N\"");
    
            for (int i = 2; i < o.Items.Count; i++)
            {
                Append(sb, "", "", o.Items[i].Sku, o.Items[i].Quantity, "", "");
                sb.AppendLine("\"Y\"");
            }
        }
    
        return sb.ToString();
    }
    
    private void Append(StringBuilder sb, params object[] items)
    {
        foreach (object item in items)
        {
            sb.Append("\"").Append(item).Append("\",");
        }
    }
    

    【讨论】:

      【解决方案3】:

      你的内部循环看起来像这样:

      for (i = 0; i < items.Count; ++i) {
        sb.Append(sku)
        sb.Append(qty)
        if (i % 2 == 1) {
          if (i == items.Count - 1) {
            sb.Append("N\n")
          } else {
            sb.Append("Y\n" "" "");
          }
        }
      }
      if (items.Count == 0) {
        sb.Append("" "" "" "" "N")
      }
      if (items.Count % 2 == 1) {
        sb.Append("" "" "N")
      }
      

      您可以扩展伪代码... csv 格式有点不寻常。通常一个 csv 将包含一个项目列表,每行一个(每个重复的订单号)。

      【讨论】:

        【解决方案4】:

        未经测试,但你明白了。在这种形式下,它可能无法完全满足您的需求,但很容易调整为您想要的。不需要所有那些 stringbuilder 废话。

        public class Order
        {
            public int ID { get; set; }
            public int Created { get; set; }
            public List<Item> Items { get; set; }
            public override string ToString()
            {
                string fakeItem = "";
                if(Items.Count > 2) 
                    fakeItem = Environment.NewLine + @""""", """", ""Y"" "; // or whatever you want.
                return string.Join(@"{0}, {1}, {2}, {3}", 
                    ID, 
                    Created == 0 ? "Y" : "N", 
                    string.Join(", ", from item in Items.Take(2) select item.ToString()),
                    fakeItem);
            }
        }
        public class Item
        {
            public string Sku { get; set; }
            public int Quantity { get; set; }
            public override string ToString()
            {
                return string.Format(@"{0}, {1}", Sku, Quantity);
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-05-07
          • 1970-01-01
          • 1970-01-01
          • 2011-07-23
          • 2017-02-18
          • 1970-01-01
          • 2016-06-22
          相关资源
          最近更新 更多