我编写了一个程序来对句子中具有x个匹配字符的单词进行计数。输入字符串是多行字符串,我只需要根据给定的标准考虑其他行。同样在那些过滤的行中,我需要进一步选择替代词,然后检查那些过滤的词是否与交叉字符匹配。
例如假设我有一个如下所示的输入字符串,并且需要查找其中有两个或更多元音的单词:
string myString = "1.In order to get a Disneyland ticket
2.that includes the new Star Wars land
3.you must stay at a Disney hotel
4.the night of or night before your visit.
5.Day passes without a hotel
6.reservation will be available after June 23";
现在让我们说我需要计算第二行中的每个第三个单词,并计算这些过滤后的单词中是否有2个或更多的元音。如果满足此条件,则返回匹配的单词数和包含这些内容的总行数 匹配的单词。
例如根据选择第二行的条件,已过滤的行将为{2,4,6}。类似地,这些经过过滤的行中的每个第3个单词将是第2行:{“ the”,“ Wars”},第4行:{“ of”,“ before”}和第6行:{“ be”,“ after”} 。
对于这些过滤的单词,具有2个或更多元音的匹配单词将在第4行的{“ before”}和第6行的单词{“ after”}}。因此最终输出将为wordCount = 2,因为这些单词来自第4行和第6行,因此总lineCount =2。
我使用嵌套的for循环编写了下面的代码,产生了所需的输出。
public static void Main(string[] args)
{
int vowelCount = 2; // match words with 2 or more vowels
int skipWord = 3; // Consider every 3rd word only
int skipLine = 2; // Consider every 2nd line only
int wordCount = 0;
int lineCount = 0;
string myString = @"1.In order to get a Disneyland ticket
2.that includes the new Star Wars land
3.you must stay at a Disney hotel
4.the night of or night before your visit.
5.Day passes without a hotel
6.reservation will be available after June 23";";
List<string> myList = myString.Split(Environment.NewLine).ToList();
List<string> lineWords = new List<string>();
char[] vowels = {'a', 'e', 'i', 'o', 'u'};
for (int i = skipLine; i <= myList.Count; i += skipLine)
{
int origWordCount = wordCount;
lineWords = myList[i - 1].Split(' ').ToList();
for (int j = skipWord; j <= lineWords.Count; j += skipWord)
{
char[] wordArr = lineWords[j-1].ToLower().ToCharArray();
int match = vowels.Intersect(wordArr).Count();
if (match >= vowelCount)
wordCount++;
}
if (wordCount > origWordCount)
lineCount++;
}
Console.WriteLine("WordCount : {0}, LineCount : {1}", wordCount, lineCount);
上面的代码效果很好,但是想知道是否有一种方法可以避免嵌套循环。我了解了linq和lambda表达式,但不确定如何在此处使用它们。
感谢所有评论。
答案 0 :(得分:1)
首先在“ where”子句中使用“谓词”过滤行,以获取第二行:
List<string> lines = myString.Split(Environment.NewLine).Where((l,index) => index % 2 != 0).ToList();
然后您将获得如下结果:
foreach (var line in lines)
{
// Get every 3rd word in the line
var thirdWords = line.Split(' ').Where((w,index) => index % 3 == 2).ToList();
// Get words with 2 or more vowels in it.
// Have you tested words that have same vowel twice?
var matchWords = thirdWords.Where(w => w.Intersect(vowels).Count() >= vowelCount).ToList();
//if words with vowels found, update 'wordCount' and 'lineCount'
if (matchWords.Any()) {
wordCount = wordCount + matchWords.Count;
lineCount++;
}
}
Console.WriteLine("WordCount : {0}, LineCount : {1}", wordCount, lineCount);
答案 1 :(得分:0)
将所有内容放在一个大型LINQ查询中是否明智?这将使理解代码,测试代码,实施更改或重用部分代码变得更加困难。
考虑编写单独的类似LINQ的函数,这些函数仅执行部分代码。这称为扩展方法。参见extension methods demystified
我需要计算第二行中的每个第3个单词,并计算这些过滤后的单词中是否有2个或更多的元音。如果满足此条件,则返回匹配的单词数和包含这些匹配单词的总行数。
因此创建函数:
其中大多数都很简单:
IEnumerable<string> ToLines(this text)
{
// TODO: check text not null
using (var reader = new StringReader(text))
{
var line = reader.ReadLine();
while (line != null)
{
yield return line;
line = reader.ReadLine();
}
}
}
IEnumerable<string> KeepEvery2ndLine(this IEnumerable<string> lines)
{
// TODO: check lines not null
int lineNr = 0;
foreach (var line in lines
{
++lineNr;
if (lineNr%2 == 0)
yield return line;
}
}
IEnumerable<string> ToWords(this string line)
{
// TODO: check line not null
// when is a word a word? do you need to consider tabs? semicolons?
// is a number like 12 a word?
}
建议:使用正则表达式将行分隔为单词。参见how to split string in words
顺便说一句:如果一个单词是“ 12”,那么它有多少个元音:零或两个? (“十二个”有两个元音)
我不会编写所有功能。你会明白的。
由于将任务分解为较小的任务,因此很容易理解每个函数应该执行的操作,易于实现,易于测试,易于更改。
有了它们,您的查询就非常简单:
var result = inputText.ToLines()
.KeepEvery2ndLine()
.ToWords()
.KeepEvery3rdWord()
.CountVowels();