如何维护句子中字符出现的列表以及它们出现在哪个单词中

时间:2019-04-12 11:16:44

标签: c#

我想构建一个分析句子的程序,然后针对出现在句子单词中的每个字符/数字/符号,记录该字符出现在哪个单词中。(大写/小写忽略,并重复一个单词中的字符条目将被忽略)。

所以如果我有一句话“我像牛一样孤独地流浪”。

  1. 第一个字之后,我将有一个数据结构... i-1; //因为在第一个单词中出现了“ I”。
  2. 第二个字之后,我的数据结构将是... i-1; w-2; a2; n-2; d-2; e-2; r-2;
  3. 第六个字之后... i-1; w-2,6; a-2,4,5; n-2,3; d-2; e-2,3; r-2; l-3; o-3,6; y-3; s-4; c-6;

这将在c#中进行。我考虑过2d数组,即26(对于字母)x 20(句子中的单词。这里的问题是我的数组将是稀疏的,并且还要努力跟踪哪个元素是下一个对每个字母备用。我希望我的字母a数组为[2,4,5]而不是[0,2,0,4,5]或[0,0,2,0,4, 5],由于还要迎合其他符号而变得复杂,因此26个将迅速变大,其中的第三个数组是“很明显”如何编程的数组,但却是最不优雅的解决方案。

 static void Main(string[] args)
        {
            string[] sentence = new string[6] { "i", "wandered", "lonely", "as", "a", "cow" };
            string alphabet = "abcdefghijklmnopqrstuvwxyz";
            int[,] letterInWord= new int[26, 7];

            for (int letterIndex = 0; letterIndex < alphabet.Length; letterIndex++)
            {
                for (int wordIndex = 0; wordIndex < sentence.Length; wordIndex++)
                {
                    if(sentence[wordIndex].IndexOf(alphabet[letterIndex]) >= 0)
                    {
                        letterInWord[letterIndex, wordIndex+1] = wordIndex+1;
                    }
                }
            }
            // then analyse or just print out (adding 1 to get counting base 1)
            for (int letterIndex = 0; letterIndex < alphabet.Length; letterIndex++)
            {
                Console.Write(alphabet[letterIndex]+ " is in word(s) " );
                for (int wordIndex = 1; wordIndex <= sentence.Length; wordIndex++)
                {
                    if (letterInWord[letterIndex, wordIndex] > 0)
                    {
                        Console.Write(letterInWord[letterIndex, wordIndex]  + " ");
                    }
                }
                Console.WriteLine();
            }
        }

那行得通,但我只是不喜欢它。

理想情况下,我想要一个名为“ senceList”的句子的列表,然后为我找到的每个字母(例如z)寻找一个名为“ listForZ”的列表,如果找不到,我会创建一个名为listForZ的新列表,将单词编号添加到列表中,然后将listForZ添加到句子列表中。

但是,这需要从我刚刚在单词中找到的变量以编程方式创建列表的名称,而我一直在努力理解其工作方式。我想我可以使用一种工厂方法模式,该模式知道我可以拥有的所有列表名称并适当地创建它们,但是同样,对于我想要的名称来说,这似乎有些过分。

有建议的路线吗?

3 个答案:

答案 0 :(得分:0)

借助正则表达式(我们必须匹配单词)和 Linq 来查询这些单词,您可以实现以下内容:

string sentence = "I wandered lonely as a cow";

var result = string.Join("; ", Regex
  .Matches(sentence, "[A-Za-z]+")  // Word is a sequence of A..Z a..z letters
  .OfType<Match>()
  .Select((match, index) => new {
    word = match.Value.ToLower(),  // So we have word, e.g. "lonely" 
    index + 1                      // and its index, e.g. "3"  
  })
  .SelectMany(item => item.word.Select(c => new {
    character = c,             // for each character 
    wordNumber = item.index    // we have a index of the word(s) where it appears
  }))
  .GroupBy(item => item.character, item => item.wordNumber) // grouping by character
  .Select(chunk => $"{chunk.Key} - {string.Join(",", chunk.Distinct().OrderBy(n => n))}"));

// Let's have a look at the results
Console.Write(result);

结果:

i - 1; w - 2,6; a - 2,4,5; n - 2,3; d - 2; e - 2,3; r - 2; l - 3; o - 3,6; y - 3; s - 4; c - 6

答案 1 :(得分:0)

使用正则表达式:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace ConsoleApplication108
{
    class Program
    {

        static void Main(string[] args)
        {
            string input = "I wandered lonely as a cow";

            string pattern = @"(?'word'\w+)\s*";

            string[] words = Regex.Matches(input, pattern).Cast<Match>().Select(x => x.Groups["word"].Value).ToArray();

            var results = words
                .Select(x => new { word = x, characters = x.ToCharArray().Select((y, i) => new { ch = y, index = i }).GroupBy(y => y.ch).Select(y => y.First()).ToList() }).ToList();

        }
    }

}

答案 2 :(得分:0)

  

但这需要以编程方式从以下位置创建列表的名称   我刚刚在单词中找到的变量,我一直在努力   了解这将如何工作。

使用Dictionary,您可以将关联。在您的情况下,单词中的字符是键,单词出现的位置是值:

Dictionary<char, List<int>> occurrences = new Dictionary<char, List<int>>();

string sentence = "I wandered lonely as a cow";
string[] words = sentence.ToLower().Split(" ".ToCharArray());
for(int i = 0; i < words.Length; i++)
{
    foreach(char c in words[i].ToCharArray().Distinct())
    {
        if (!occurrences.ContainsKey(c))
        {
            occurrences.Add(c, new List<int>());
        }
        occurrences[c].Add(i + 1);
    }
}

foreach(KeyValuePair<char, List<int>> kvp in occurrences)
{
    Console.WriteLine(kvp.Key.ToString() + " - " + String.Join(",", kvp.Value.ToArray()));
}

生成的输出:

i - 1
w - 2,6
a - 2,4,5
n - 2,3
d - 2
e - 2,3
r - 2
l - 3
o - 3,6
y - 3
s - 4
c - 6