【问题标题】:Exclude Similarities in List of Strings to extract the Difference排除字符串列表中的相似性以提取差异
【发布时间】:2018-04-09 00:37:12
【问题描述】:

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

如何遍历列表并排除相似之处以查找书名?

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

《蝇王》这本书很经典。
《杀死一只知更鸟》这本书是经典之作。
《麦田里的守望者》这本书很经典。


我遇到的问题是我不能简单地使用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
}

我的想法是将列表中的所有字符串相互比较,排除字符串的相似部分,并留下标题。但我不知道该怎么做。

【问题讨论】:

  • 相反,这似乎是使用正则表达式的完美时间。 this 是你要找的吗?
  • 我是否理解正确,在您的源数据中,包含书名的句子中有许多不同的前缀和后缀?不只是"The book named "" is a classic."
  • @Enigmativity 是的,它可以是许多不同的前缀和后缀。但我总是在列表中添加类似的匹配字符串。
  • 如果你的句子列表总是相似的,你可以只使用 Substring 来获取值,如果不是创建一个前缀和后缀列表,然后为每个句子循环通过前缀和后缀找到匹配.找到匹配项后,您可以使用 sentence[x].Substring() 使用匹配项的长度解析出标题。
  • 如果它们始终相同,您也可以使用 .Replace 并将前缀和后缀替换为空字符串。

标签: c#


【解决方案1】:

这是一个有趣的问题,所以我玩了一下,想出了以下(麻烦的)解决方案:

找到任何句子具有不同字符的第一个索引, 然后在相反的句子中做同样的事情, 然后使用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.

【讨论】:

  • 它在我的项目中运行良好。如果字符串中的后缀丢失,您知道如何将其更改为仍然有效吗?
  • 如果没有后缀you don't need to change anything.。如果只有部分句子有后缀,那就更难了。
  • 它应该可以正常工作。它们都应该是相似的,所以如果缺少一个后缀,所有的都会。
  • 太好了,很高兴能帮上忙。我敢打赌你知道下一步该做什么:-)
  • 为了效率,我会改变两件事:1)不反转字符串 2)循环会比 linq 查询更快
【解决方案2】:

使用 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 的标题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-19
    • 1970-01-01
    • 1970-01-01
    • 2015-02-07
    • 2020-06-23
    • 2023-01-09
    • 1970-01-01
    相关资源
    最近更新 更多