【问题标题】:Splitting a C# List<T> Into Two将 C# List<T> 拆分为两个
【发布时间】:2010-08-18 15:56:16
【问题描述】:

我正在使用 C# 和 ASP.NET 3.5。基本上我正在从数据集中检索一列数据并将其放入列表中,如下所示:

    List<String> dates = new List<String>();

    foreach (DataRow rowMonth in myDS.Tables[0].Rows)
    {
        string ListedMonthYear = (string)rowMonth[0];
        dates.Add(ListedMonthYear);
    }

返回值为:

 Apr-10
 Mar-10
 Feb-10
 Jan-10
 Dec-09
 Nov-09
 Oct-09

我有兴趣将这些值分成两个列表,以便将来对它们执行操作。

Apr   |  2010
Mar   |  2010
Feb   |  2010
Jan   |  2010
Dec   |  2009
Nov   |  2009
Oct   |  2009

最好的方法是什么?

编辑:rowMonth 只是包含所有日期相关值的数据行 - 月-年、月开始、月结束、活动月或非活动月。基本上我只是想提取第一列月-年进行操作并忽略其余部分。

【问题讨论】:

  • rowMonth[0] 的类型是什么?
  • @Andrey:显然可以转换为string
  • @dtb 是的,但是如果是日期时间,首先将其转换为字符串是一种巨大的浪费,如果不是日期时间,它应该是。
  • @dtb Joel 解释了我的问题背后的原因
  • 是的,它不是日期时间,它更像是从 db 的数据集中返回的 nvarchar 数据。

标签: c# asp.net generics list


【解决方案1】:

您可以使用 LINQ:

var months = (from item in dates
              select item.Substring(0, 3))
             .ToList();

var years  = (from item in dates
              select 2000 + int.Parse(item.Substring(4, 2)))
             .ToList();

您可能更喜欢将这两个部分分别存储在同一个列表中:

var result = (from item in dates
              select Tuple.Create(item.Substring(0, 3),
                                  2000 + int.Parse(item.Substring(4, 2))))
             .ToList();

【讨论】:

  • 我想你的意思是item.Substring(0, 3))
  • @Yuriy Faktorovich:确实如此。谢谢。
  • 我认为 Tuple 可能是 2010 年的功能 - 2008 年有类似的东西吗?
  • @firedrawndagger:不,但是您可以轻松定义自己的包含字符串和整数的类。
【解决方案2】:

这样您就不会遍历列表两次。但它只适用于 2k 年及以上,我假设您希望将年数作为整数列表。

List<string> months = new List<string>();
List<int> years = new List<int>();


dates.ForEach(s =>
            {
                months.Add(s.Substring(0, 3));
                years.Add(2000 + int.Parse(s.Substring(4, 2)));
            });

【讨论】:

  • ToList 仅适用于 ForEach?老兄!
  • @dtb 我的印象是基准测试比执行 foreach 循环更快。
  • +1 这是性能更好的代码,尽管我们不知道列表是否会变得非常大。
  • @Yuriy Faktorovich: enumerable.ToList().ForEachforeach (var x in enumerable) 快?有趣的。链接?
  • @dtb:我已经完成了基准测试,我目前的版本是最快的。它结合了我们的两个答案。我正在寻找 ToList().ForEachforeach 的基准。
【解决方案3】:

如果您只有 2000 年之后的日期,您可以执行以下操作:

dates.Select(d => d.Split('-')).Select(parts => new { Month = parts[0], Year = "20"+parts[0]})

【讨论】:

  • 到时候我早就走了,所以这不是我的问题!!我想如果我编写的任何代码持续到 2100 年,我将成为一个传奇,以至于 DateTime 问题不会成为问题。 讽刺>
  • 是的,他们在 1965 年就是这么说的。
  • 我当然希望我不必再支持这个应用程序 90 年。
【解决方案4】:

我会考虑使用DateTime 对象而不是string,这样您就可以即时导出日期/时间表示,而不必维护两个列表。

比如你原来的解析方法可以改成下面这样。

List<DateTime> dates = new List<DateTime>();

foreach (DataRow rowMonth in myDS.Tables[0].Rows)
{
    DateTime rowDate = DateTime.Parse(rowMonth[0]);
    dates.Add(rowDate);
}

然后要产生两个需要的列表,你可以使用linq如下。

// Converting to lists to demonstrate, though may not be required in your app.
List<short> years = dates.Select(d => d.Year).ToList();
List<string> months = dates.Select(d =>
    CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(d.Month)).ToList();

请注意,这并不是您想要的,因为有一些小警告。

  • 如果行中的日期不是众所周知的日期格式,DateTime.Parse 可能需要使用格式字符串进行定制。
  • GetMonthName() 返回完整的月份名称;您可以破解一个解决方案来获取字符串的前三个字符,但可能有一个更优雅的解决方案。

【讨论】:

  • +1。如果这个项目可以使用DateTimes 而不是strings,那就去做吧。获取单个时间组件更有意义,也更容易,而不必依赖创建子字符串。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多