代码之家  ›  专栏  ›  技术社区  ›  Matt Mitchell

使用linq,如何过滤字符串列表中与模式“q1,q2”等匹配的值?

  •  0
  • Matt Mitchell  · 技术社区  · 15 年前

    这应该是一个简单的答案,但我正在寻找最好的答案,至少要考虑到性能和优雅。

    我有一张弦和 一些 其中值的形式为q1、q2、q3等。

    我想选择这些。

    最好的方法是什么?

    3 回复  |  直到 15 年前
        1
  •  1
  •   Jay Bazuzi Buck Hodges    15 年前

    似乎你在尝试微优化,这意味着你将花费大量精力使你的程序运行相同的速度。首先关注代码的清晰性,然后优化实际缓慢的代码。

    假设您已经分析并发现这是应用程序在现实场景中的瓶颈:

    使用它是不雅的(通常是性能上的拖累) 非特殊情况例外 病例。见 http://www.developerfusion.com/code/4650/validating-an-integer/ 例如。

    根据情况的限制,你最好改变一下 IsInteger() 做下列之一:

    bool int.TryParse(string s, out int result);
    

    (见 http://msdn.microsoft.com/en-us/library/system.int32.tryparse.aspx )

    或:

    Microsoft.VisualBasic.Information.IsNumeric(object expression)
    

    (见 http://www.hanselman.com/blog/ExploringIsNumericForC.aspx )

    x >= '0' && x < '9'
    

    然后:

    .Where(c => c[0] == 'q' && IsInteger(c[1]))
    
        2
  •  1
  •   Community CDub    7 年前

    最好的答案是使用regex或 Jay Bazuzi's int.TryParse suggestion .

    举个简单的例子,试试这个 LINQPad :

    void Main()
    {
        int n = 100;
    
        string[] a = {"q2", "q3", "b"};
        a = a.Concat(Enumerable.Repeat(0,n).Select(i => "qasd")).ToArray(); /* Random data */
    
        /* Regex Method */
        System.Text.RegularExpressions.Regex r = new System.Text.RegularExpressions.Regex("^q[0-9]+$");
        List<string> regMethod = a.Where(c => r.IsMatch(c)).ToList().Dump("Result");
    
        /* IsInteger Method */
        List<string> intMethod = a.Where(c => c.StartsWith("q") && IsInteger(c.Substring(1))).ToList().Dump("Result");
    
        /* int.TryParse Method suggest by Jay Bazuzi */
        int e = 0;
        List<string> parseMethod = a.Where(c => c.StartsWith("q") && int.TryParse(c.Substring(1), out e)).ToList().Dump("Result");
    }
    
    public static bool IsInteger(string theValue)
    {
       try
       {
           Convert.ToInt32(theValue);
           return true;
       } 
       catch 
       {
           return false;
       }
    }
    

    尝试一次对两个方法中的一个进行注释,并尝试对n的不同值进行性能测试。

    我的经验(在我的Core2 Duo笔记本电脑上)似乎表明:

    n = 100. Regex takes about 0.003 seconds, IsInteger takes about 0.01 seconds
    n = 1,000. Regex takes about 0.004 seconds, IsInteger takes about 0.07 seconds
    n = 10,000. Regex takes about 0.007 seconds, IsInteger takes about 0.67 seconds
    n = 100,000. Regex takes about 0.046 seconds, IsInteger takes about 6.9 seconds
    n = 1,000,000. Regex takes about 0.42 seconds, IsInteger takes about 1 minute and 6 seconds
    

    ParseMethod与Regex具有相同的性能(如果在代码示例中以内联方式执行,则速度稍快,如果在单独的方法中执行,则速度稍快,即替换Isinteger方法体)。

    注意:创建字符串的成本不包括在内(如果愿意,请插入日期差异),但这两种方法的成本相同。

    如果大多数键不带“q”(从未调用isinteger),那么这些数字就更接近了,但regex是好的或更好的。 即使是在这种情况下

    即(对于“asdasd”而不是“qasd”的填充字符串):

    n = 100. Regex takes about 0.003 seconds, IsInteger takes about 0.003 seconds
    n = 1,000. Regex takes about 0.004 seconds, IsInteger takes about 0.004 seconds
    n = 10,000. Regex takes about 0.005 seconds, IsInteger takes about 0.005 seconds
    n = 100,000. Regex takes about 0.023 seconds, IsInteger takes about 0.025 seconds
    n = 1,000,000. Regex takes about 0.21 seconds, IsInteger takes about 0.22 seconds
    

    同样,parsemethod具有与regex相同的性能。

    结论: 使用regex或typarse,在最坏的情况下会更快,否则也会更快。

    但是,是否有更好/更快的方法从字符串集合中选择int值?也许是一个以某种方式编译得更快的通用过滤器?

        3
  •  1
  •   Meta-Knight    15 年前

    ISinteger的瓶颈可能是由于try-catch。

    我尝试用胰蛋白酶替代Isinteger,得到以下结果(n=1000000):

    Regex方法:540 ms

    胰蛋白酶法:537 ms

    我对第二种方法使用了以下代码:

    Func<string, bool> lambda = (string c) => { Int32 temp; 
                                        return c.StartsWith("q") 
                                        && int.TryParse(c.Substring(1),out temp); };
    List<string> intMethod = a.Where(lambda).ToList();
    

    故事的寓意是…

    虽然我通常喜欢使用regex,但在这个简单的情况下,字符串操作很简单,台盼色解决方案是完全可以接受的。从性能上讲,使用哪种方法并不重要,但不要使用异常处理来检查某个字符串值是否是int!