C# 如何将列表归结为最不常用的字符串?

C# 如何将列表归结为最不常用的字符串?,c#,C#,我有一个HashSet,我正在将粗俗的单词加载到其中进行过滤。问题是,我的列表将包含“符”以及完整拼写的单词。我想做的是过滤列表,使其只包含“Fu”,这将从列表中删除该词的任何其他形式 换句话说,我想删除列表中的所有字符串,其中其子字符串也是列表项 我该怎么做呢 我有以下内容,其中excludedWords是原始的HashSet,但它不能完全工作: HashSet<string> copy = new HashSet<string>(exludedWords); for

我有一个
HashSet
,我正在将粗俗的单词加载到其中进行过滤。问题是,我的列表将包含“符”以及完整拼写的单词。我想做的是过滤列表,使其只包含“Fu”,这将从列表中删除该词的任何其他形式

换句话说,我想删除列表中的所有字符串,其中其子字符串也是列表项

我该怎么做呢

我有以下内容,其中
excludedWords
是原始的
HashSet
,但它不能完全工作:

HashSet<string> copy = new HashSet<string>(exludedWords);

foreach (string w in copy)
{
    foreach (string s in copy)
    {
        if (w.Contains(s) && w.Length > s.Length)
        {
            result.Remove(w);
        }
    }
}
HashSet copy=新的HashSet(排除字);
foreach(复制中的字符串w)
{
foreach(复制中的字符串s)
{
如果(w.包含和w.长度>s.长度)
{
结果:移除(w);
}
}
}

您应该将集合中的每个单词与集合中的每个其他(明显不同的)单词进行比较。您可以通过以下方式实现这一点(尽管我确信无论如何,这不是最有效的方法):

string[]strings={“a”、“aa”、“aaa”、“b”、“bb”、“bbb”、“c”、“cc”、“ccc”};
列表结果=新列表(字符串);
foreach(字符串中的字符串str1){
foreach(字符串中的字符串str2){
如果(str1!=str2){
if(str2.Contains(str1)){
结果:移除(str2);
}
}
}
}
返回结果;
这里有一种方法

filter.RemoveAll(a => filter.Any(b => b != a && a.Contains(b)));
其中filter是一个列表,预先填充了过滤器字符串

编辑:
没有看到您希望包含而不是以开始。所以做了必要的修改

假设您只想丢弃较长的值,您可以使用
IEqualityComparer
实现来获取新的值集

private class ShortestSubStringComparer : IComparer<string>, IEqualityComparer<string>
{
    public int Compare(string x, string y)
    {
        if (x == null) return (y == null) ? 0 : -1;
        if (y == null) return 1;

        Debug.Assert(x != null && y != null);
        if (this.Equals(x, y)) return x.Length.CompareTo(y.Length);
        return StringComparer.CurrentCulture.Compare(x, y);
    }

    public bool Equals(string x, string y)
    {
        if (x == null) return y == null;
        if (x.StartsWith(y)) return true;
        if (y != null && y.StartsWith(x)) return true;
        return false;
    }

    public int GetHashCode(string obj)
    {
        return obj.GetHashCode();
    }
}
或者,
Min
可能会起作用(这意味着您也不需要
IComparer
实现)

public HashSet FindShortestSubString(HashSet集)
{
var comparer=新的ShortestSubStringComparer();
返回新的HashSet(set.GroupBy(e=>e,comparer)。选择(g=>g.Min(e=>e));
}

我建议不要使用这种类型的过滤。您可能会节省一些cpu周期,但您会得到一些意想不到的结果,这些结果可能会让您的用户感到困惑(或者干脆让他们发疯)

例如,让我们假设这是您的粗俗词汇列表

福 酒吧 笨蛋 愚蠢的

您希望从某些内容中过滤掉所有这些单词。为了提高效率,您删除foohead和傻瓜,只需在子字符串foo上进行过滤

您将过滤包含foo但不在原始粗俗列表中的无害单词

让我想起了最近的每日WTF。。。(第二个倒下)


您可以使用正则表达式。这是在vb,但我相信你可以转换它

例如:

Imports System.Text.RegularExpressions
Public Class Form1

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim InputString As String
        InputString = Regex.Replace(WHAT THE USER HAS ENTERED, "fu", "**")
    End Sub
End Class

你要过滤掉所有以“Fu”开头的单词,还是我误解了?@bzlm我会说“从列表中删除所有包含其他单词的单词”,所以。。。删除foohead,因为foo已在列表中?应使用作为数据结构。搜索字符串的效率会更高。@Jeff:我想这应该是一个答案。从这个数据结构来看,该算法几乎可以自己编写。-StartsWith()是不够的,但您的示例确实建议了一种与我不同的方法。复制原始列表并处理副本,而不是修改原始列表。我试试。@MAW74656,使用Contains而不是StartsWith的理由是什么?为什么要删除“astrofunk”,因为“fu”在列表中?@bzlm-因为“fu”是“astrofunk”和“fu*k”中最短的常用攻击子串。我从来没有说过只从开始移除,子字符串可以从字符串中的任何索引开始。很抱歉,根据您的“fu”示例,我将其解释为
StartsWith
,但您可以同样轻松地使用
Contains
@MAW74656-我刚刚使用
string[]strings={“as”,“ASS”,“AS5”}运行了上面的代码片段
作为输入,我得到的结果就是
as
。不确定那里可能出了什么问题。如果你改变了条件,那可能就是原因-哎哟,兰姆达!这会比循环更好吗?不会,但我当时没有可用的Assember编辑器来提供性能最好的解决方案。(我没有看到他在帖子中提到任何速度的需要)-我只是说,一般来说,哪一种表现更好?我知道这并不完美,尽管因为我只做了一次,然后在缩短的列表中循环,所以此操作的性能并不重要。这并不是最快的,因为它是n^2(所有项与所有其他项和自身进行比较),而替代解决方案永远不会检查比其自身短的字符串。我只是喜欢它的紧凑性和可读性与其他人相比,如果你只有一个小的数据库的话,我相信它会好的。-我的名单可以有几个“最小公域”。我需要去掉较长版本的单词。听起来这个方法假设每个列表只有一个最不常见的存根字符串?这就是我对这个问题的评论。除非我误解了OP将如何处理这个减少的粗俗词汇列表,否则他会有这个问题的。是的。我同意。这是一个有效的编程练习,值得一个真正的答案。但是对于这个用例,它会导致一些真正的问题。对不起,我没有看到问题?我看到的唯一问题是这个过滤器会抛出一些安全的词(这是可以接受的)。我不在乎我的列表是否包含“食物”,只要它不包含“foohead”。问题不在于列表中的内容。你的名单是正确的。当您试图使用列表对用户提交的内容进行过滤时(我们假设您正在进行过滤,我们可能是错的)@BZink,我认为这样做是为了确保随机生成的字符串不可能包含粗俗内容。不筛选网页。:)谢谢,但我真的不想“隐藏”ba
public HashSet<string> FindShortestSubString(HashSet<string> set)
{
    var comparer = new ShortestSubStringComparer();
    return new HashSet<string>(set.GroupBy(e => e, comparer).Select(g => g.OrderBy(e => e, comparer).First()));
}
public HashSet<string> FindShortestSubString(HashSet<string> set)
{
    var comparer = new ShortestSubStringComparer();
    return new HashSet<string>(set.GroupBy(e => e, comparer).Select(g => g.Min(e => e)));
}
Imports System.Text.RegularExpressions
Public Class Form1

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim InputString As String
        InputString = Regex.Replace(WHAT THE USER HAS ENTERED, "fu", "**")
    End Sub
End Class