【问题标题】:How to create a List<T> from a comma separated string?如何从逗号分隔的字符串创建 List<T>?
【发布时间】:2010-10-28 22:46:55
【问题描述】:

给定变量

string ids = Request.QueryString["ids"]; // "1,2,3,4,5";

有什么方法可以将其转换为列表而不做类似的事情

List<int> myList = new List<int>();

foreach (string id in ids.Split(','))
{
    if (int.TryParse(id))
    {
        myList.Add(Convert.ToInt32(id));
    }
}

【问题讨论】:

  • 您能否指定您想要的行为 - 是否如上所示,即默默地忽略不是 Int32 的位?没有一个答案考虑到这一点......
  • 我默默地忽略了错误的 ID,因为它们是由想要将某些图像拉到他们的页面上的内容编辑器输入的,但是我可以在该字段上进行验证以阻止这种情况发生,我想跨度>
  • 是的,这正是我所暗示的......
  • 这个几乎重复的stackoverflow.com/questions/911717/…,从 6 小时后开始,专门要求一串数字,所以它有一个简单的答案。

标签: c# generics


【解决方案1】:

使用 Linq:

myList.AddRange(ids.Split(',').Select(s => int.Parse(s));

或直接:

var myList = ids.Split(',').Select(s => int.Parse(s));

另外,为了防止编译器显式生成(大部分是冗余的)lambda,请考虑:

var myList = ids.Split(',').Select((Func<string, int>)int.Parse);

(提示:微优化。)

还有TryParse 应该被使用而不是Parse(仅)如果无效输入是可能的并且应该被静默处理。但是,其他人使用TryParse 发布了解决方案,所以我当然不会。请记住,您不应该重复计算。

【讨论】:

  • 这样你得到一个布尔值列表。 Int32.TryParse 返回一个布尔值。
  • 最后两个示例的另一个问题实际上是它们返回 IEnumerable
  • @Konrad,我加入并为您解决了这个问题。希望你不介意;)
  • 小心,这里需要TryParse
  • @Ruben,我已经回滚到 Konrad 的原始答案,但我不确定这是否更可取。使用 TryParse 意味着代码不会编译,使用 Parse 意味着它会编译,但如果/当它在运行时遇到错误 ID 时会导致异常。
【解决方案2】:

要从头开始创建列表,请使用 LINQ:

ids.Split(',').Select(i => int.Parse(i)).ToList();

如果您已经拥有列表对象,请省略 ToList() 调用并使用 AddRange:

myList.AddRange(ids.Split(',').Select(i => int.Parse(i)));

如果字符串中的某些条目可能不是整数,则可以使用 TryParse:

int temp;
var myList = ids.Split(',')
    .Select(s => new { P = int.TryParse(s, out temp), I = temp })
    .Where(x => x.P)
    .Select(x => x.I)
    .ToList();

一种避免 temps/TryParse 但跳过无效条目的最终(较慢)方法是使用 Regex:

var myList = Regex.Matches(ids, "[0-9]+").Cast<Match>().SelectMany(m => m.Groups.Cast<Group>()).Select(g => int.Parse(g.Value));

但是,如果您的条目之一溢出 int (999999999999),这可能会引发。

【讨论】:

  • 我已经编辑了我的答案以反映内联 TryParse 实现所需的内容。这就是 Convert.ToNullableInt32 实现会有帮助的地方:)
  • 你确定编译(在 LINQPad 中:D)
  • 是的。我唯一不能 100% 确定的是属性初始化程序中的操作顺序('out temp' 后跟 I = temp)。我相信保证会按顺序执行。
  • 同意它应该从 exec 命令 POV 工作,但我讨厌像这样的东西共享的临时工。扩展/辅助方法是解决所有这些问题的方法。
  • 从这个几乎重复的问答 stackoverflow.com/a/911729/292060 的评论中,Select(i =&gt; int.Parse(i)) 部分可以简化为 Select(int.Parse)
【解决方案3】:

这应该可以解决问题:

myList.Split(',').Select(s => Convert.ToInt32(s)).ToList();

如果列表可能包含除整数之外的其他数据,则应包含TryParse 调用。查看接受的答案。

【讨论】:

  • 那么,同样的评论不使用 TryParse :P (但撤消 -1!)
  • 是的,TryParse 不包括在内,因为数据是一个查询字符串,它应该在那里。但感谢您撤消 -1 :)
【解决方案4】:

这里的一个问题是我们将如何处理不是整数的值(假设我们会得到一些不是整数的值)。一个想法可能是简单地使用正则表达式:

^-?[0-9]+$

现在,我们可以将所有这些结合起来(如 Konrad 的示例所示):

var myList = ids.Split(',').Where(s => Regex.IsMatch(s, "^-?[0-9]$")).Select(s => Convert.ToInt32(s)).ToList();

这应该可以完成工作。

【讨论】:

  • Regex 不是说 [1-9]+,但如果是的话,它仍然可能超出范围并抛出 - 与 tryparse 不同。
  • 关于超出范围 - 非常正确。但是,我不明白您为什么要将正则表达式更改为 [1-9]+,这会将数字“10”变成无效数字。此外,我将稍微修改正则表达式以考虑负数。
  • 抱歉,我的意思是 [0-9],(我的意思是 \d)。只是提出“两个问题”的指控,同时指出代码更复杂,并且与正则表达式不同。您的正则表达式在 [0-9] 之后仍然没有“+”,因此只能使用 1 位数字,因此永远不会脱离 raqnge:P
【解决方案5】:

或在您的示例中包括TryParse

var res = ids.Split(',').Where(x => { int tmp; return int.TryParse(x, out tmp); }).Select(x => int.Parse(x)).ToList();

【讨论】:

    【解决方案6】:

    为了在性能特征和行为方面匹配请求,它应该做同样的事情,而不是退出正则表达式或不做'TryParse':-

    ds.Split(',')
      .Select( i => {
        int value; 
        bool valid = int.TryParse(out value); 
        return new {valid, value}
      })
      .Where(r=>r.valid)
      .Select(r=>r.value)
      .ToList();
    

    虽然是正确的,但这很丑:D

    借用 Jason 评论中的提示:-

    ds.Split(',')
      .Select( i => {
        int value; 
        bool valid = int.TryParse(out value); 
        return valid ? new int?( value) : null;
      })
      .Where(r=>r != null)
      .Select(r=>r.Value)
      .ToList();
    

    或者

    static class Convert
    {
      public static Int32? ConvertNullable(this string s)
      {
        int value; 
        bool valid = int.TryParse(out value); 
        return valid ? new int?( value) : null;
      }
    }
    
    ds.Split(',')
      .Select( s => Convert.ConvertNullable(s))
      .Where(r=>r != null)
      .Select(r=>r.Value)
      .ToList();
    

    【讨论】:

    • 使用内联声明 Select 的部分可能会稍微简单一些 .Select(s =&gt; int.TryParse(s, out int d)? (int?)d : null)
    猜你喜欢
    • 2010-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-27
    • 1970-01-01
    相关资源
    最近更新 更多