【问题标题】:C# find anagram from a string array of candidatesC# 从候选字符串数组中查找字谜
【发布时间】:2021-11-19 21:59:55
【问题描述】:

我的任务是实现一个可以返回正确的字谜子列表的方法。

到目前为止,我无法弄清楚如何在candidates 中收集与word 匹配的字谜并将其返回。

这是我现在的代码:

    public class Anagram
    {
        public string word;

        public Anagram(string sourceWord)
        {
            if (sourceWord is null)
            {
                throw new ArgumentNullException(nameof(sourceWord));
            }

            if (sourceWord.Length == 0)
            {
                throw new ArgumentException(null);
            }

            this.word = sourceWord;
        }

        public string[] FindAnagrams(string[] candidates)
        {
            if (candidates is null)
            {
                throw new ArgumentNullException(nameof(candidates));
            }

            char[] char1 = this.word.ToLower().ToCharArray();
            Array.Sort(char1);
            string newWord1 = new string(char1);
            string newWord2;
            string[] result = new string[candidates.Length];

            for (int i = 0; i < candidates.Length; i++)
            {
                char[] char2 = candidates[i].ToLower().ToCharArray();
                Array.Sort(char2);
                newWord2 = char2.ToString();

                if (newWord1 == newWord2)
                {
                    result[i] = candidates[i];
                }
            }

            return result;
        }
    }

我应该在if 语句中执行第二个for 循环还是其他什么?

顺便说一句,我是如何使用我的类构造函数的,这是我第一次尝试使用它,最后我认为我没有正确调用 sourceWord 变量..

这是我稍后需要通过的测试场景之一:

        [TestCase("master", new[] { "stream", "pigeon", "maters" }, ExpectedResult = new[] { "stream", "maters" })]
        [TestCase("listen", new[] { "enlists", "google", "inlets", "banana" }, ExpectedResult = new[] { "inlets" })]
        [TestCase("allergy", new[] { "gallery", "ballerina", "regally", "clergy", "largely", "leading" }, ExpectedResult = new[] { "gallery", "regally", "largely" })]
        public string[] FindAnagrams_Detects_Anagrams(string word, string[] candidates)
        {
            var sut = new Anagram(word);
            return sut.FindAnagrams(candidates);
        }

很遗憾,无法在此任务上使用 LINQ。

【问题讨论】:

    标签: c# arrays for-loop constructor anagram


    【解决方案1】:

    如果两个单词是字谜,它们有相同相同个字母:

     art ~ rat ~ tar
    

    我们可以对每个单词中的字母进行排序,并通过这些键对单词进行分组:

     ...
     aaabnn: banana
     aemrst: maters, stream
     ...
    

    代码:

    using System.Linq;
    
    ...
    
    // Given list of (candidates) word return anagrams
    public static IEnumerable<string[]> FindAnagrams(IEnumerable<string> candidates) {
      if (null == candidates)
        throw new ArgumentNullException(nameof(candidates));
    
      return candidates
        .GroupBy(word => string.Concat(word.OrderBy(c => c)))
        .Where(group => group.Count() > 1)
        .Select(group => group.OrderBy(word => word).ToArray());
    }
    

    演示:

    string[] demo = new string[] {
      "stream", "pigeon", "maters",
      "enlists", "google", "inlets", "banana",
      "gallery", "ballerina", "regally", "clergy", "largely", "leading",
      "art", "tar", "rat"
    };
    
    string report = string.Join(Environment.NewLine, FindAnagrams(demo)
      .Select(group => string.Join(", ", group)));
    
    Console.Write(report);
    

    结果:

    maters, stream
    gallery, largely, regally
    art, rat, tar
    

    编辑:FindAnagrams_Detects_Anagrams 的想法相同:

      public string[] FindAnagrams_Detects_Anagrams(string word, string[] candidates) {
        if (word == null || candidates == null)
          return new string[0];
    
        string[] wordArr =  
    
        string key = string.Concat(word.OrderBy(c => c)); 
    
        return candidates
          .Where(w => w != null)
          .Where(w => key == string.Concat(w.OrderBy(c => c)))
          .ToArray(); 
      }  
    

    如果你愿意,你可以摆脱 Linq:

    所有字谜:

    public static IEnumerable<string[]> FindAnagrams(IEnumerable<string> candidates) {
      if (null == candidates)
        throw new ArgumentNullException(nameof(candidates));
    
      Dictionary<string, List<string>> groups = 
        new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
    
      foreach (var word in candidates) {
        char[] keyArray = word.ToCharArray();
    
        Array.Sort(keyArray);
    
        string key = string.Concat(keyArray);
    
        if (groups.TryGetValue(key, out var list))
          list.Add(word);
        else
          groups.Add(key, new List<string>() { word});
      }
    
      foreach (var pair in groups) {
        if (pair.Value.Count > 1) {
          string[] result = new string[pair.Value.Count];
    
          for (int i = 0; i < pair.Value.Count; ++i)
            result[i] = pair.Value[i];
    
          yield return result;
        }
      }
    }
    

    检测字谜:

    public string[] FindAnagrams_Detects_Anagrams(string word, string[] candidates) {
      if (word == null || candidates == null)
        return new string[0];
    
      char[] keyArray = word.ToCharArray();
    
      Array.Sort(keyArray);
    
      string key = string.Concat(keyArray);
    
      List<string> list = new List<string>();
    
      foreach (string w in candidates) {
        char[] wArray = w.ToCharArray();
    
        Array.Sort(wArray);
    
        string wKey = string.Concat(wArray);
        
        if (string.Equals(wKey, key, StringComparison.OrdinalIgnoreCase)) 
          list.Add(w);
      }
    
      string[] result = new string[list.Count];
    
      for (int i = 0; i < list.Count; ++i)
        result[i] = list[i];
    
      return result;
    }
    

    【讨论】:

    • 但是有没有不使用 LINQ 的解决方案?
    • @Linascts:如果你愿意,你可以轻松摆脱 Linq;请看我的编辑
    • 最后一种方法非常适合我,它确实有效。但是我想知道如何检测不敏感的情况?例如[TestCase("Orchestra", new[] { "cashier", "Carthorse", "radishes" }, ExpectedResult = new[] { "Carthorse" })][TestCase("orchestra", new[] { "caregivers", "Carthorse", "radishes" }, ExpectedResult = new[] { "Carthorse" })] 我们可以用一些if 语句来优化它吗?
    • 我忘了提敏感部分。我为此道歉。 @dmitry
    • @Linascts:为了忽略大小写,您可以使用if (string.Equals(wKey, key, StringComparison.OrdinalIgnoreCase)) 而不是if (wKey, key)。在FindAnagrams 中,您可以在创建字典时指定StringComparer.OrdinalIgnoreCase。我已经编辑了答案
    猜你喜欢
    • 2017-01-16
    • 2014-10-24
    • 2014-04-13
    • 1970-01-01
    • 2021-09-16
    • 2012-02-16
    • 2012-03-20
    • 2015-12-23
    • 2014-01-17
    相关资源
    最近更新 更多