如何将列表简化为最不常见的字符串?

时间:2011-10-03 20:28:19

标签: c#

我有一个HashSet<string>我正在加载粗俗的单词以进行过滤。问题是我的列表将包含“Fu”以及完全拼写的单词。我想要做的是过滤列表,使它只包含“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);
        }
    }
}

5 个答案:

答案 0 :(得分:3)

您应该将集合中的每个单词与集合中的每个单词(明显不同的)进行比较。您可以按照以下方式完成此操作(尽管我确信这不是最有效的方法,但无论如何):

string[] strings = { "a", "aa", "aaa", "b", "bb", "bbb", "c", "cc", "ccc" };
List<string> results = new List<string>(strings);

foreach (string str1 in strings) {
  foreach (string str2 in strings) {
    if (str1 != str2) {
      if (str2.Contains(str1)) {
        results.Remove(str2);
      }
    }
  }
}

return results;

答案 1 :(得分:1)

这是一种方式......

filter.RemoveAll(a => filter.Any(b => b != a && a.Contains(b)));

其中filter是List并预先填充了过滤器字符串。

编辑:  没有看到你想要包含而不是开始。所以做了必要的mod。

答案 2 :(得分:1)

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

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();
    }
}

然后你的函数可以使用GroupBy函数来分组并选择第一个有序的项目,如下所示:

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()));
}

或者可能Min可能会发挥作用(意味着你也不需要IComparer<string>实现)......

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)));
}

答案 3 :(得分:1)

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

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

FOO 酒吧 foohead foolery

您希望从某些内容中过滤掉所有这些字词。为了提高效率,你可以删除foohead和foolery,然后只对子字符串foo进行过滤。

你要过滤包含foo但不在你的orignal粗俗列表中的无害单词。

让我想起最近的每日WTF ......(第二次下来)

http://thedailywtf.com/Articles/Progree-of-enail-Status.aspx

答案 4 :(得分:0)

您可以使用正则表达式。这是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