首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >定制Contains()函数

定制Contains()函数
EN

Code Review用户
提问于 2016-04-05 16:17:36
回答 2查看 406关注 0票数 0

我有以下的功能,我想知道是否有人能想出更有效率的东西。

它只需拆分内容和搜索字符串,并确定在成为真之前需要匹配多少单词。

例如,

代码语言:javascript
复制
"A dog can run.".ContainsV2("Red Dog Run", 4) = false

"A dog can run.".ContainsV2("Red Dog Run", 2) = true

"A dog can run.".ContainsV2("Red Dog Run") = true

"A dog can run.".ContainsV2("Red Dog Run", MatchAllWords: true) = false
代码语言:javascript
复制
/// <summary>
/// Checks to see if any of the words are contained in the string. 
/// </summary>
/// <param name="content"></param>
/// <param name="SearchString">Search string</param>
/// <param name="NumberOfMatches">Specify how many words have to match in the search string.
///  This value is automatically dropped when the user searches less words.
/// I.e. NumberOfMatches = 3 and the user searches 'Bob', NumberOfMatches gets set to 1.</param>
/// <param name="MatchAllWords">If set to true, all of the words in the search string must be contained in what's being checked</param>
/// <returns></returns>
public static bool ContainsV2(this string content, string SearchString, int NumberOfMatches = 1, bool MatchAllWords = false)
{
    var matches = 0;
    var numberOfWords = SearchString.Split(' ').Length;
    // Update required number of matches
    NumberOfMatches = NumberOfMatches > numberOfWords ? 
                    numberOfWords : 
                    NumberOfMatches;

    if (!string.IsNullOrEmpty(content) && !string.IsNullOrEmpty(SearchString))
    {
        SearchString.Split(' ')
            .ToList()
            .ForEach(w => //Gets the index of each word after being split
                matches += content
                    .IndexOf(
                        StripNonAlphaNumeric(w), 
                        StringComparison.OrdinalIgnoreCase
                    ) >= 0 ? 1 : 0
            );
    }
    if (MatchAllWords)
    {
        return matches == numberOfWords;
    }
    return matches >= NumberOfMatches;
}
EN

回答 2

Code Review用户

回答已采纳

发布于 2016-04-05 19:23:35

关于您的代码的几点评论:

方法应该有有意义的名称。您的扩展方法看起来更新(更好?)已经存在的Contains方法的版本,但是扩展方法做的不是原始的。一个更好的,有意义的名字是ContainsWords

你的论点也可以这样说。在我看来,SearchString并没有涵盖这个论点的意义。wordsToMatch更合适。我重命名了其他参数,就像您在代码中看到的那样。

参数名应该是骆驼壳骆驼壳

扩展方法只接受包含要匹配的单词的字符串。为了方便使用,我会添加一个重载,它需要一个单词集合。

下面是我对它的看法:

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Linq;

public static class StringExtensions
{
    public static bool ContainsWords(this String source, IEnumerable<String> wordsToMatch, int matchAtLeast = 1, bool matchAll = false)
    {
        if(wordsToMatch == null)
        {
            throw new ArgumentNullException();
        }

        var sourceWords = GetWords(source);

        var matches = sourceWords.Intersect(wordsToMatch, StringComparer.CurrentCultureIgnoreCase);

        if(matchAll || wordsToMatch.Count() < matchAtLeast)
        {
            return matches.Count() == sourceWords.Count();
        }

        return matches.Count() >= matchAtLeast;     
    }

    public static bool ContainsWords(this String source, String wordsToMatch, int matchAtLeast = 1, bool matchAll = false)
    {
        if(wordsToMatch == null)
        {
            throw new ArgumentNullException();
        }

        return source.ContainsWords(GetWords(wordsToMatch), matchAtLeast, matchAll);
    }

    // Splits string in individual words.
    private static IEnumerable<String> GetWords(String source)
    {
        return source.Split(new [] {' '}, StringSplitOptions.RemoveEmptyEntries)
            .Select(x => x.Trim('.'));
        // Optionally: trim other punctuation.
    }
}

关于效率的

更新

在您的代码中,将搜索字符串拆分两次。这不是很有效率。接下来,您将对搜索字符串中的每个单词在源字符串上使用IndexOf。这也不是很有效率。我不太擅长算法分析,但我的猜测是,将源和单词分开来匹配,然后在结果数组上应用Intersect是更有效的。

票数 1
EN

Code Review用户

发布于 2016-04-05 19:14:26

这是我的第一篇评论。看看你能做什么!我给你留下了评论。他们总是讨论下面的代码。

将文档标记保持为空是不好的风格。要么没有param标记,要么用适当的描述填充所有内容:

代码语言:javascript
复制
/// <param name="content"></param>
/// <param name="SearchString">Search string</param>
/// <param name="NumberOfMatches">Specify how many words have to match in the search string.

在我看来,太多的实施细节:

代码语言:javascript
复制
/// This value is automatically dropped when the user searches less words.
/// I.e. NumberOfMatches = 3 and the user searches 'Bob', NumberOfMatches gets set to 1.</param>

自明名称:

代码语言:javascript
复制
/// <param name="MatchAllWords">If set to true, all of the words in the search string must be contained in what's being checked</param>

这是不言自明的,删除行:

代码语言:javascript
复制
/// <returns></returns>

使用一个更有说服力的名字,比如ContainsWords:

代码语言:javascript
复制
public static bool ContainsV2(this string content, string SearchString, int NumberOfMatches = 1, bool MatchAllWords = false)
{
    var matches = 0;
    var numberOfWords = SearchString.Split(' ').Length;

不要使用空注释,如“设置变量”或“更新值”。更好地解释它,或者省略评论:

代码语言:javascript
复制
    // Update required number of matches

接线员很难理解,这里没有必要。相反,请在我的评论中使用如下所示:

代码语言:javascript
复制
    // if (NumberOfMatches > numberOfWords)
    // {
    //    NumberOfMatches = numberOfWords;
    // }
    NumberOfMatches = NumberOfMatches > numberOfWords ? 
                    numberOfWords : 
                    NumberOfMatches;

您已经拆分了上面的搜索字符串。要么不检查null,要么在开始时执行它:

代码语言:javascript
复制
    if (!string.IsNullOrEmpty(content) && !string.IsNullOrEmpty(SearchString))
    {

这太让人困惑了。降低复杂性和嵌套深度:

代码语言:javascript
复制
        SearchString.Split(' ')
            .ToList()
            .ForEach(w => //Gets the index of each word after being split
                matches += content
                    .IndexOf(
                        StripNonAlphaNumeric(w), 
                        StringComparison.OrdinalIgnoreCase
                    ) >= 0 ? 1 : 0
            );
    }

而是在函数的开头设置它。这里令人困惑的是:

代码语言:javascript
复制
    if (MatchAllWords)
    {
        return matches == numberOfWords;
    }
    return matches >= NumberOfMatches;
}
票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/124848

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档