排除字符串列表中的相似性以提取差异

时间:2018-04-08 04:10:52

标签: c#

除了书的标题外,我有一个相同的句子列表。

如何循环浏览列表并排除相似之处以查找书名?

(这是一个例子,它可以是任何具有相似性的短句。)

  

这本名为蝇王的书是经典之作   这本名为To Kill a Mockingbird的书是经典之作   这本名为The Catcher in the Rye的书是经典之作。

我遇到的问题是我不能简单地使用regexContains()来查找句子中的标题,因为我不知道下一句或书的内容标题将是。我正在从外部来源搜索许多内容,所以我想我可以提取相似词之间的内容。

The book named 麦田里的守望者 is a classic

List<string> sentences = new List<string>() { };
List<string> titles = new List<string>() { };

sentences.Add("The book named Lord of the Flies is a classic.");
sentences.Add("The book named To Kill a Mockingbird is a classic.");
sentences.Add("The book named The Catcher in the Rye is a classic.");

foreach (String title in sentences)
{
    // what to do here?

    // add title to titles list
}

我的想法是将列表中的所有字符串相互比较,排除字符串的相似部分,然后保留标题。但我不知道如何去做。

2 个答案:

答案 0 :(得分:3)

这是一个有趣的问题,所以我已经玩了一下,并提出了以下(繁琐的)解决方案:

找到第一个索引,其中任何句子都有不同的字符, 然后在反向句子中做同样的事, 然后使用Substring仅提取句子的不同部分:

List<string> ExtractDifferences(List<string> sentences)
{
    var firstDiffIndex = GetFirstDifferenceIndex(sentences);
    var lastDiffIndex = GetFirstDifferenceIndex(sentences.Select(s => new string(s.Reverse().ToArray())).ToList());
    return sentences.Select(s => s.Substring(firstDiffIndex, s.Length - lastDiffIndex - firstDiffIndex)).ToList();
}


int GetFirstDifferenceIndex(IList<string> strings)
{
    int firstDifferenceIndex = int.MaxValue;

    for (int i = 0; i < strings.Count; i++)
    {
        var current = strings[i];
        var prev = strings[i == 0 ? strings.Count - 1 : i - 1];

        var firstDiffIndex = current
            .Select((c, j) => new { CurrentChar = c, Index = j })
            .FirstOrDefault(ci => ci.CurrentChar != prev[ci.Index])
            .Index;

        if (firstDiffIndex < firstDifferenceIndex)
        {
            firstDifferenceIndex = firstDiffIndex;
        }
    }
    return firstDifferenceIndex;
}

我想GetFirstDifferenceIndex方法可以用不同的方式编写,也许使用linq更好,但我没有足够的时间来使用它。

You can see a live demo on rextester.

答案 1 :(得分:0)

使用LINQ的工作解决方案:

List<string> sentences = new List<string>() { };
List<string> titles = new List<string>() { };

sentences.Add("The book named Lord of the Flies is a classic.");
sentences.Add("The book named To Kill a Mockingbird is a classic.");
sentences.Add("The book named The Catcher in the Rye is a classic.");
sentences.Add("Hello");
sentences.Add("The book named ");


titles = sentences.Where(sentence => sentence.Length > "The book named ".Length + " is a classic".Length)
            .GroupBy(sentence => sentence.Substring(0, 15), sentence => sentence.Remove(sentence.Length - " is a classic".Length).Substring("The book named ".Length))
            .Where(g => g.Key == "The book named ")
            .SelectMany(g => g)
            .ToList();

foreach (var title in titles)
    WriteLine(title);

首先,它过滤掉的句子太短而不符合标准,然后将结果按前15个字母分组,并用String.Remove提取标题。