问题 使用LINQ从字符串中删除字符


我正在尝试通过编写一些简单的扩展方法来刷新我的LINQ。有没有更好的方法来编写如下函数从字符串中删除给定的字符列表(使用LINQ)?

它帮助我思考LINQ首先依赖的扩展方法:

public static string Remove(this string s, IEnumerable<char> chars)
{
    string removeChars = string.Concat(chars);

    return new string(s.ToCharArray().Where(c => !removeChars.Contains(c)).ToArray());
}

但那很难看。 Ergo LINQ。

我在LINQ语句中注意到的差异是我必须使用'select'而使用扩展方法,我不必这样做。

/// <summary>Strip characters out of a string.</summary>
/// <param name="chars">The characters to remove.</param>
public static string Remove(this string s, IEnumerable<char> chars)
{
    string removeChars = string.Concat(chars);

    var stripped = from c in s.ToCharArray()
                   where !removeChars.Contains(c)
                   select c;

    return new string(stripped.ToArray());
}

所以我想知道这个(上面的最后一个片段)是否是用于完成字符删除的最简洁的LINQ语句。


12472
2018-01-16 04:28


起源

我不能让其中任何一个在测试中工作。也许我做错了,但测试两者,在字符串“长鳍金枪鱼”和字符a,b,c我希望“绝杀”,但我得到“lbco”。 - Chris Missal
@Chris Missal:很奇怪,我预计两种情况都会有结果。 - Alexander Prokofyev


答案:


我希望第一种形式的扩展方法虽然简化为

public static string Remove(this string s, IEnumerable<char> chars)
{
    return new string(s.Where(c => !chars.Contains(c)).ToArray());
}

至于 选择 关键字,它是第二种形式的强制性。该 文件 说什么“查询表达式必须以select子句或group子句终止”。这就是为什么我会避免使用LINQ语法糖。


12
2018-01-16 05:36





尝试这是为了简洁

public static string Remove(this string source, IEnumerable<char> chars) {
  return new String(source.Where(x => !chars.Contains(x)).ToArray());
}

编辑

更新以更正它从源中删除重复项


1
2018-01-16 05:19



不幸的是,这将从源中删除所有重复项,即使它们不在字符中。例如,如果source ==“abcabc”和chars ==“a”,则仅返回“bc”而不是“bcbc”。 - Alexander Prokofyev
@Alexander,感谢你指出这一点。我忘了除了这个行为 - JaredPar


就个人而言,我倾向于使用非关系情境的第一种语法。当我需要执行关系操作(连接)时,比如表达式树对SQL,我使用后者。但是,这只是因为它在一段时间内使用SQL更具可读性。


1
2018-01-16 13:21





使用stringBuilder而不是新字符串时,性能会有所提高。以下结果为:

StringBuilder 00:00:13.9930633 新字符串00:00:15.1495309

        string s = "ababababajjjaazsiajjsoajiojsioajlmmzaaokpdahgffaiojsia";
        var sw = new Stopwatch();
        sw.Start();
        var toRemove = new char[] { 'j', 'a', 'z' };
        for (int i = 0; i < 1000000; i++)
        {
            StringBuilder sb = new StringBuilder(s.Length, s.Length);
            foreach (var c in s) if (!toRemove.Contains(c)) sb.Append(c);
        }
        Console.WriteLine("StringBuilder " + sw.Elapsed);
        sw.Restart();
        for (int i = 0; i < 1000000; i++)
        {
            new string(s.Where(c => !toRemove.Contains(c)).ToArray());
        }
        Console.WriteLine("new String " + sw.Elapsed);

0
2018-01-13 16:08