【问题标题】:Find different word between two strings在两个字符串之间查找不同的单词
【发布时间】:2012-03-01 20:07:09
【问题描述】:

我有很多短语,例如

"Nola jumped off the cliff"
"Loroy jumped off the cliff"
"Nola jumped off the couch"
"Leroy lept off the couch"

我需要在一个短语中找到一个不同单词的每个点,并将该单词添加到一个节点,该节点是一个可以在短语中该位置使用的单词列表。所以我们最终会得到。

"Node1(1) Node2(1) off the Node3(1)"
"Node1(2) Node2(1) off the Node3(1)"
...etc

其中节点 1 代表名称列表 (Nola,Leroy),节点 2 代表动作列表 (jumped,lept),节点 3 最终代表位置列表 (cliff,couch)

这个想法是获取一个短语列表,并让它自动创建节点,并用短语中可以在该节点处使用的单词填充它。

那么,第一,我将如何生成短语节点列表?我一直无法弄清楚如何比较两个句子,看看它们是否完全一样减去一个单词。

第二次设置节点后,比较所有节点组合以得出新匹配的最佳方法是什么? (希望有道理)

【问题讨论】:

  • “我需要找到一个短语中的每个点,它是一个不同的单词”——不同于 what
  • 您可以使用 string.Split() 将每个字符串拆分为一个 string[] 并使用空格作为分隔符。然后比较结果数组中的每个字符串。
  • 您可以为句子中的每个单词位置创建“节点列表”,遍历所有样本,并收集您的节点。然后你可以折叠所有只包含一个单词的节点(在你的例子中,位置 3 和 4 的节点)。
  • 您可能希望从解决最长公共子序列问题开始。我在这里有一个 JavaScript 解决方案的草图;应该很容易适应C#:blogs.msdn.com/b/ericlippert/archive/2004/07/21/189974.aspx

标签: c# string comparison


【解决方案1】:

不错,我喜欢。由于您使用 C# 标记了您的问题,因此我也在 C# 中编写了答案。

获取两个短语之间不同单词的快速方法:

string phrase1 = "Nola jumped off the cliff";
string phrase2 = "Juri jumped off the coach";

//Split phrases into word arrays
var phrase1Words = phrase1.Split(' ');
var phrase2Words = phrase2.Split(' ');

//Find the intersection of the two arrays (find the matching words)
var wordsInPhrase1and2 = phrase1Words.Intersect(phrase2Words);

//The number of words that differ 
int wordDelta = phrase1Words.Count() - wordsInPhrase1and2.Count();

//Find the differing words
var wordsOnlyInPhrase1 = phrase1Words.Except(wordsInPhrase1and2);
var wordsOnlyInPhrase2 = phrase2Words.Except(wordsInPhrase1and2);

您可以节省自己的时间并使用内置的 LINQ 函数 Intersect、Except 等,而不是通过循环和检查每个元素来匹配元素...

随机造词请参考NominSim的回答。

【讨论】:

  • 我以前从未见过相交,这是一件很漂亮的事情。
  • 抱歉,我花了这么长时间才选择正确答案,我被一个新项目牵制了,才回到这个项目。
【解决方案2】:

另一个基于 Linq 的解决方案可以生成所有可能的组合:

var phrases = new List<string> {
           "Nola jumped off the cliff",
           "Loroy jumped off the cliff",
           "Nola jumped off the couch",
           "Leroy lept off the couch"
                           };

var sets = (from p in phrases
            from indexedWord in p.Split(' ').Select((word,idx) => new {idx,word})
            group indexedWord by indexedWord.idx into g
            select g.Select(e => e.word).Distinct()).ToArray();


var allCombos = from w1 in sets[0]
                from w2 in sets[1]
                from w3 in sets[2]
                from w4 in sets[3]
                from w5 in sets[4]
                select String.Format("{0} {1} {2} {3} {4}.", w1, w2, w3, w4, w5);

不会写出最易读的代码,但写起来很有趣。 =)

【讨论】:

    【解决方案3】:

    首先生成这样的列表应该可以:

            HashSet<String>[] NodeList = new HashSet<String>[phraseLength];
            for (int i = 0; i < phraseLength; i++)
            {
                NodeList[i] = new HashSet<string>();
            }
    
            foreach (String phrase in PhraseList)
            {
                string[] phraseStrings = phrase.Split(' ');
                for (int i = 0; i < phraseLength; i++)
                {
                    if(!NodeList[i].Contains(phraseStrings[i]))
                    {
                        NodeList[i].Add(phraseStrings[i]);
                    }
                }
            }
    

    然后,当您创建句子时,您可以简单地遍历 NodeList 并从每个节点中选择一个字符串,如果您想随机执行,可能是这样的:

            String sentence = "";
            foreach (HashSet<String> Node in NodeList)
            {
                Random rand = new Random();
                sentence += Node.ToArray()[rand.Next(0, Node.Count)];
            }
    

    应该注意,如果您需要随机访问 HashSet,它可能不是最好的主意。

    【讨论】:

      猜你喜欢
      • 2011-12-26
      • 2014-10-18
      • 2011-11-20
      • 2017-04-07
      • 2021-11-13
      • 1970-01-01
      • 2015-04-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多