【问题标题】:Parsing string into int[] using Linq [closed]使用 Linq 将字符串解析为 int[] [关闭]
【发布时间】:2020-03-06 13:46:55
【问题描述】:

我来自this 问题,但我的字符串中也可能存在无效值。 例如

string input = "1;2;3;4;5;6x;7;8;9;1x0";

应该是[1,2,3,4,5,7,8,9],因为["6x", "1x0"]是无效的整数值

我的做法:https://dotnetfiddle.net/Ji4bzq

string i = "1;2;3;4;5;6x;7;8;9;1x0";
int temp = -1;
int[] r = i.Split(';').Where(x => int.TryParse(x, out  temp)).Select(_ => temp).ToArray();

这似乎可行,但感觉有点不对,因为 Select(_ => temp) 部分。

问题:在可读性和可靠性方面有没有更好的方法? (AsParallel 应该在这里失败)

【问题讨论】:

    标签: c# arrays string linq parsing


    【解决方案1】:

    如果使用 C# 7.0,那么您可以使用 var out feature:

    var result = input.Split(';').Select(s => (int.TryParse(s, out int v), v))
                      .Where(pair => pair.Item1)
                      .Select(pair => pair.v);
    

    不知道这是否或多或少可读,但我个人更喜欢避免这些副作用临时变量。 至于关于它更长的评论,也许只有int.TryParse(s, out int v) ? v : null - 那么这将导致Nullable<int> 的集合而不是整数,所以取决于你喜欢什么。

    【讨论】:

    • Split(";") 不正确... :) Type-o 也许是 '?
    • @Çöđěxěŕ - 已更正。太习惯python了
    • 我认为它不是更具可读性:)
    • @Dr.Snail 根据but feels kinda wrong because of that Select(_ => temp),您的解决方案是否有效,如果有效,瓶颈是什么,已经执行了哪些测试来证明是否有效?还有可读性问题,老派循环怎么样,易于维护和理解;无论如何,linq 将所有这些都抛在脑后 :)
    • @Dr.Snail “我的意思是你把 105 变成了 125 个字符的代码” 除了实际的答案,更短的代码并不意味着它更易读。最好更具表现力,并明确说明正在发生的事情。
    【解决方案2】:

    使用TryParse() 样式方法的主要问题当然是它们使用了out 参数,这与Linq 不兼容。

    因此,我们实际上使用简单的辅助方法进行解析,它返回元组而不是使用out 参数。

    例如:

    public static class Parse
    {
        public static (bool wasSuccessful, int value) TryParse(string text)
        {
            bool success = int.TryParse(text, out var value);
            return (success, value);
        }
    }
    

    然后您可以使用Parse.TryParse 而不是int.TryParse(),IMO 通常会使代码更具可读性(尽管不会更短)。

    使用上面的示例,您可以编写如下代码:

    var r = input.Split(';')
       .Select(Parse.TryParse)
       .Where(parse => parse.wasSuccessful)
       .Select(parse => parse.value)
       .ToArray();
    

    或者,如果您更喜欢 Linq 查询语法(我有时觉得它更易读,但 YMMV):

    var s = (
        from   item in input.Split(';')
        let    parse = Parse.TryParse(item)
        where  parse.wasSuccessful
        select parse.value
    ).ToArray();
    

    (虽然我确实觉得结尾的ToArray()有点丑……)

    【讨论】:

      【解决方案3】:

      这是使用Regex 的替代解决方案。

      模式((?<=;)|^)[0-9]*((?=;)|$) 匹配被; 包围的数字;

      Try it out

      string i = "1;2;3;4;5;6x;7;8;9;1x0";
      string pattern = "((?<=;)|^)[0-9]*((?=;)|$)";
      int[] r = Regex.Matches(i, pattern).Cast<Match>().Select(x => int.Parse(x.Value)).ToArray();
      

      【讨论】:

        【解决方案4】:

        这是一个使用 nullables 的替代版本:

        string i = "1;2;3;4;5;6x;7;8;9;1x0";
        int[] r = i.Split(';')
           .Select(s => int.TryParse(s, out int v) ? (int?) v : null)
           .Where(j => j.HasValue) 
           .Select(j => j.Value)  
           .ToArray();            
        

        哪个更易读是个人品味的问题。有些人更喜欢循环而不是 linq。

        【讨论】:

          【解决方案5】:

          使用 ValueTuples 的 Gilad 出色答案的修改版和更易读的版本:

          var integers = input.Split(';')
                              .Select(_ => (Success: int.TryParse(_, out var n), IntegerValue: n))
                              .Where(_ => _.Success)
                              .Select(_ => _.IntegerValue);
          

          【讨论】:

            猜你喜欢
            • 2021-01-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-10-07
            相关资源
            最近更新 更多