【问题标题】:What's the best way to split a list of strings to match first and last letters?拆分字符串列表以匹配第一个和最后一个字母的最佳方法是什么?
【发布时间】:2014-03-28 18:59:36
【问题描述】:

我在 C# 中有一个很长的单词列表,我想在该列表中找到所有单词的首尾字母相同,并且长度介于 5 到 7 个字符之间。例如,列表可能有:

“浪费了被洗了洗了洗了看着手表枯萎了”

它会返回

长度:5-7,第一个字母:w,最后一个字母:d,“浪费、洗涤、观看” 长度:5-7,第一个字母:w,最后一个字母:s,“washes, watch, wilts, wastes”

然后我可能会将规范更改为 3-4 个字符的长度,这将返回

长度:3-4,第一个字母:w,最后一个字母:s,“was, wits”

我发现这种拆分方法非常快,使每个项目都独一无二,使用长度并给出了一个很好的开始: Spliting string into words length-based lists c#

有没有办法修改/使用它来考虑第一个和最后一个字母?

编辑

我最初询问“最快”的方式是因为我通常使用大量字符串数组(速度慢且涉及大量代码)来解决此类问题。 LINQ 和查找对我来说是新的,但我可以看到我链接到的解决方案中使用的 ILookup 的简单性和速度非常快。我实际上并不需要最少的处理器时间。任何避免我为这些信息创建单独数组的方法都很棒。

【问题讨论】:

  • 可能有。你有什么问题,要我们为你写代码吗?
  • “最快”?噗。为什么不使用 Where 然后使用 GroupBy?现代 CPU 非常快;在编写完成这项工作的内容之后,然后对其进行分析以查看它是否需要“更快”。 Where/GroupBy 方法在复杂性方面也非常有效。
  • 我不知道什么会更快,因为我看到人们发布的大多数答案都涉及 Linq,但另一种选择可能是正则表达式......
  • 感谢您的反馈,我已经对其进行了修改,去掉了“最快”这个词,并且我已经解释了我上面想说的内容。

标签: c# string list lookup ilookup


【解决方案1】:

这一条线将为您提供在您的范围内具有相同第一个/最后一个字母的组

 int min = 5;
 int max = 7;
 var results = str.Split()
                     .Where(s => s.Length >= min && s.Length <= max)
                     .GroupBy(s => new { First = s.First(), Last = s.Last()});

【讨论】:

  • 这是一个了不起的解决方案。还有一个问题:您如何将其概括为一系列长度?所以不是只做 5 作为最小值和 7 作为最大值,它还会做 6 和 8、7 和 9 等,因为它适用于整个单词列表?
  • @user3473853:如果您的字长限制不相交(即 5-7、8-10 等),那么您可以扩展答案以构建嵌套分组。如果长度限制重叠(即 5-7、6-8、7-9),那么您必须使用多个查询来完成。
【解决方案2】:
var minLength = 5;
var maxLength = 7;
var firstPart = "w";
var lastPart = "d";

var words = new List<string> { "washed", "wash" }; // so on

var matches = words.Where(w => w.Length >= minLength && w.Length <= maxLength && 
                               w.StartsWith(firstPart) && w.EndsWith(lastPart))
                   .ToList();

在大多数情况下,这应该足够快,除非您要处理数万个单词并担心 ms。那么我们可以进一步观察。

【讨论】:

    【解决方案3】:

    我在 LINQPad 中创建了这个:

    void Main()
    {
    var words = new []{"wasted", "was", "washed", "washing", "was", "washes", "watched", "watches", "wilts", "with", "wastes", "wits", "washings"};
    
    var firstLetter = "w";
    var lastLetter = "d";
    var minimumLength = 5;
    var maximumLength = 7;
    
    var sortedWords = words.Where(w => w.StartsWith(firstLetter) && w.EndsWith(lastLetter) && w.Length >= minimumLength && w.Length <= maximumLength);
    sortedWords.Dump();
    }
    

    如果这还不够快,我会创建一个查找表:

    Dictionary<char, Dictionary<char, List<string>> lookupTable;
    

    然后做:

    lookupTable[firstLetter][lastLetter].Where(<check length>)
    

    【讨论】:

      【解决方案4】:

      这是一种完全符合您要求的方法。你只得到一个字符串列表和最小/最大长度,对吗?您没有获得过滤的第一个和最后一个字母。此方法处理字符串中的所有第一个/最后一个字母。

      private static void ProcessInput(string[] words, int minLength, int maxLength)
      {
          var groups = from word in words
                       where word.Length > 0 && word.Length >= minLength && word.Length <= maxLength
                       let key = new Tuple<char, char>(word.First(), word.Last())
                       group word by key into @group
                       orderby Char.ToLowerInvariant(@group.Key.Item1), @group.Key.Item1, Char.ToLowerInvariant(@group.Key.Item2), @group.Key.Item2
                       select @group;
          Console.WriteLine("Length: {0}-{1}", minLength, maxLength);
          foreach (var group in groups)
          {
              Console.WriteLine("First letter: {0}, Last letter: {1}", group.Key.Item1, group.Key.Item2);
              foreach (var word in group)
                  Console.WriteLine("\t{0}", word);
          }
      }
      

      【讨论】:

        【解决方案5】:

        作为一个快速的想法,我不知道这是否会比发布的 linq 解决方案更快或更有效,但这也可以使用正则表达式相当容易地完成。

        例如,如果您想获得以“w”开头并以“s”结尾的 5-7 个字母长度的单词,您可以使用以下模式:

        \bw[A-Za-z]{3,5}s\b
        

        (这可以很容易地被更多变量驱动 - 例如,为第一个字母、最小长度、最大长度、最后一个字母设置一个变量并将它们插入到模式中以替换 w、3、5 和s)

        他们,使用 RegEx 库,然后您可以将捕获的组作为您的列表。

        同样,我不知道这在效率方面与 linq 相比如何,但我认为它可能值得一提。

        希望这会有所帮助!

        【讨论】:

        • 但是您需要运行 676 (26*26) 个不同的正则表达式来确保获得所有匹配项,并且您需要某种分组逻辑。运行所有正则表达式的开销会影响您的性能。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-21
        • 2015-01-11
        • 2014-08-12
        • 1970-01-01
        • 2014-08-15
        • 2017-04-23
        相关资源
        最近更新 更多