【问题标题】:Using LINQ remove vowels from string使用 LINQ 从字符串中删除元音
【发布时间】:2014-02-20 09:01:57
【问题描述】:

我想从字符串数组中删除元音,我用 foreach 循环做到了,但现在 想要使用 LINQ 或 Lambda 表达式来执行它

我试过以下代码 LINQ

string[] strArray = new string[] { "cello", "guitar", "violin"};
string[] vowels = new string[] { "a", "e", "i", "o", "u" };

var vNovowels = from vitem in strArray
                from vowel in vowels
                where vitem.Contains(vowel)
                select vitem.Replace(vowel, "");

foreach (var item in vNovowels)
{
    Console.WriteLine(item); 
}

但我没有得到预期的结果。

我通过上述查询得到的输出是:-

cllo
cell
guitr
gutar
gitar
voln
vilin

期望的输出:

cll
gtr
vln

【问题讨论】:

  • 这不是 lambda 表达式,而是 LINQ 查询。
  • @OndrejJanacek 这是一个查询。他不是试图修改现有集合,而是根据源集合中的值创建一个新集合。如果那不行,那么像select 这样的投影操作就没有意义了。

标签: c# lambda


【解决方案1】:

您可以使用正则表达式来匹配所有元音并用空字符串替换它们,从而非常有效地完成此操作:

var strArray = new List<string> { "cello", "guitar", "violin" };
var pattern = @"[aeiou]";
var noVowels = strArray.Select(item => 
                  Regex.Replace(item, pattern, "", RegexOptions.IgnoreCase));
foreach (var item in noVowels) {         
    Console.WriteLine(item); 
}

这将返回您正在寻找的输出。

您最初的尝试没有奏效,因为它针对其中包含的每个唯一元音单独评估每个单词。

更新:我对这个解决方案与Mathias' HashSet&lt;char&gt; based solution (benchmark code here) 进行了一些基本的基准测试,包括 Regex 版本的编译和非编译版本。我针对 2582 个 lorem-ipsum 单词的数组运行它,针对集合迭代 1000 万次(因此大约 250 亿单词),在 LinqPad 中运行它,平均运行 3 次:

                  Init Each Time              Init One Time
                avg ms      % diff          avg ms     % diff
Regex            586          +1%            586          -
Regex Compiled   581          -              593         +1%
HashSet         2550        +339%            641        +10%

事实证明,如果你只初始化HashSet 和模式string 一次,那么它们的性能非常相似。 Regex 击败 Hashset,但仅勉强(超过 250 亿字快 80 毫秒),Regex Compiled 和 Noncompiled 的性能几乎相同。但是,如果每次运行 HashSet 时都对其进行初始化,那么它会降低 HashSet 方法的性能。

要点是,如果您想使用HashSet 方法,请务必为您要排除的每组字符初始化一次HashSet

【讨论】:

  • 为什么在元音不存在时尝试替换?
  • @RoyiNamir 如果 Regex.Replace 仍然这样做,为什么要明确检查元音是否存在?
  • @RoyiNamir,他正在迭代每个单词而不是每个字母。
  • @RoyiNamir 我认为您可能误解了正则表达式的工作方式。它遍历标记所有模式匹配的字符串,然后一次完成所有替换(在 StringBuilder 中构建下一个字符串)。将此与 String.Replace 进行比较,后者正在左右分配新字符串。
  • @RoyiNamir 再次查看Regex.Replace 的代码。它首先匹配模式(类似于string.Contains),然后运行Replace 函数。如果没有匹配项,Replace 函数不会执行任何操作。
【解决方案2】:

虽然Yaakov's reg-ex solution在优雅和效率方面要好很多,但为了学习,你可以使用Where

string[] strArray = new string[] { "cello", "guitar", "violin" };
var vowels = new HashSet<char>("aeiou"); // or: { 'a', 'e', 'i', 'o', 'u' };

var vNovowels2 = from vitem in strArray
                 select new string(vitem.Where(c => !vowels.Contains(c)).ToArray());

foreach (var item in vNovowels2)
{
    Console.WriteLine(item);
}

【讨论】:

  • 我原以为HashSet 会比正则表达式更有效。我觉得你的也更优雅!
  • @Sam 我很感激。为了检查速度,我快速(并且原始地)对我的和 Yaakov 的速度进行了基准测试,分别用秒表运行了一百万次,结果发现 reg-ex 方法大约需要我的时间的 38%...
  • 仅供参考:我向my answer添加了一些基准
  • 或:var vowels = new HashSet&lt;char&gt;("aeiou");
【解决方案3】:

正则表达式替换是最好的方法。

string[] strArray = new string[] { "cello", "guitar", "violin" };

var rx = new Regex("^a|e|i|o|u", RegexOptions.IgnoreCase);

var vNovowels = from vitem in strArray
                select rx.Replace(vitem, string.Empty);

foreach (var item in vNovowels)
{
    Console.WriteLine(item);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-23
    • 2021-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-04
    • 1970-01-01
    相关资源
    最近更新 更多