如何将字符串数组中的每个单词按字母顺序添加到列表中


string[] words = new string[5] { "abbey","billowy", "chills","abced","abcde" }; 

它应该只显示:

修道院翻腾的寒意abcde

我试过这个代码

List<string> AlphabeticOrder = new List<string>();
foreach (var word in words)
{
for (int i = 1; i < word.Length; i++)
{
if (word[i] < word[i - 1])
{
break;
}
AlphabeticOrder.Add(word);
break;
}
}

一线解决方案:

var alphabeticOrder = words.Where(w => Enumerable.SequenceEqual(w.OrderBy(x => x), w)).ToList();

编辑:正如评论中所指出的,这种方法在性能方面并不是最理想的,所以如果这是一个优先事项,可以考虑其他答案中提出的解决方案。

如果你把它分解成碎片,这会变得更容易。您需要的是一个函数,该函数接收字符串并告诉字符串中的字符是否按字母顺序排列。

例如:

public static class CharacterSequence // I didn't think hard about the name
{
public static bool CharactersAreInAlphabeticalOrder(string input)
{
return input.SequenceEqual(input.OrderBy(c => c));
}
}

完成后,下一部分只是检查字符串的集合,并只返回那些字符有序的字符串。如果string是字符的集合(char)。此方法获取字符序列并对其进行排序。然后将原始字符与排序后的字符进行比较。如果它们是相同的,那么原始序列是有序的。

var wordsWithCharactersInOrder = 
words.Where(CharacterSequence.CharactersAreInAlphabeticalOrder);

这样分解它有帮助的一个原因是它更容易理解。阅读上面的代码并说出它的作用是非常容易的。此外,如果您意识到您想要更改按顺序检查字符的方式,您可以在较小的函数中进行更改。

例如,您可能意识到原来的函数是区分大小写的。C在d之前,但d在C之前。在这个例子中,它不那么引人注目,因为函数很小,但随着逻辑变得越来越复杂,当我们将事物分解成更小的函数时,阅读和思考变得更容易。不区分大小写的版本将是

public static bool CharactersAreInAlphabeticalOrder(string input)
{
var lowerCase = input.ToLower();
return lowerCase.SequenceEqual(lowerCase.OrderBy(c => c));
}

如果你想更进一步,那么你可以一次比较一个字符,而不是对整个字符串进行排序。

public static bool CharactersAreInAlphabeticalOrder(string input)
{
if (input.Length < 2) return true;
var lowerCase = input.ToLower();
var characterIndexes = Enumerable.Range(0, input.Length - 1);
return characterIndexes.All(characterIndex => 
lowerCase[characterIndex] <= lowerCase[characterIndex + 1]);
}

你也可以为它编写单元测试。如果你知道较小的函数总是返回预期的结果,那么检查字符串集合的较大函数将返回正确的结果。

下面是一个单元测试的例子。用这种方式测试很多条件并确信函数有效要比编辑代码并反复运行容易得多。如果你意识到还有另一种情况需要说明,你可以添加它。

[DataTestMethod]
[DataRow("A", true)]
[DataRow("AB", true)]
[DataRow("abc", true)]
[DataRow("aBc", true)]
[DataRow("ba", false)]
public void CharactersAreInAlphabeticalOrder_returns_expected_result(string input, bool expected)
{
var result = CharacterSequence.CharactersAreInAlphabeticalOrder(input);
Assert.AreEqual(expected, result);
}

我的原始代码中有一个小错误。如果一个单词只有两个字母,那是行不通的。如果没有测试,这个错误可能会进入应用程序而不会被注意到,直到以后发现和修复需要更长的时间。有了测试就容易多了。

按字母顺序排列的单词被称为初学者。

你的算法的难点是打破嵌套循环。有不同的策略来解决这个问题:

  • 使用带标签的语句和goto。后藤不高兴
  • 布尔保护的使用。这还可以,但可读性不太好
  • 将内部循环放入方法中。这是我决定提出的清晰易读的解决方案

让我们创建一个辅助方法:

private static bool IsAbecedarianWord(string word)
{
for (int i = 1; i < word.Length; i++) {
if (word[i] < word[i - 1]) {
return false;
}
}
return true;
}

在它的帮助下,我们可以写:

foreach (var word in words) {
if (IsAbecedarianWord(word)) {
AlphabeticOrder.Add(word);
}
}

干净简单!


C#中命名约定的一个注意事项。通常的惯例是(简而言之):

  • 类型名称、方法名称和属性名称都是用PascalCase编写的。接口附加地以大写I(IPascalCase)作为前缀
  • 方法参数和局部变量的名称用camelCase编写
  • 字段名(类和结构变量)是用_camelCase编写的,并带有前导下划线

考虑到这一点,我建议将AlphabeticOrder重命名为abecedarian

如果您想使用您的方法,请尝试添加以下内容:

foreach (var word in words)
{
for (int i = 1; i < word.Length; i++)
{
if (word[i] < word[i - 1])
{
break;
}
if (i == word.Length - 1)
{
AlphabeticOrder.Add(word);
}
}
}

代码中的问题是,它会检查前两个字母,如果它们是按字母顺序排列的,它会将它们添加到列表中。

这没有按预期工作的原因是关于是否丢弃结果的逻辑有缺陷。迭代单词中字母的for循环只检查第一个字母,然后退出循环,不管结果如何。

我在下面为您的函数添加了注释,以帮助解释这一点。

for (int i = 1; i < word.Length; i++)
{
if (word[i] < word[i - 1]) // check the 2nd letter of the word against the 1st
{
break; // if the 2nd letter comes before the 1st in the alphabet, exit
}
AlphabeticOrder.Add(word); // add the word to the list
break; // exit the for loop
}

您应该重构代码,使其在将单词添加到按字母顺序排列的单词列表之前检查单词的每个字母。如果条件失败,您仍然可以提前结束for循环。

有几种方法可以解决这个问题,你可以追踪上面亚当回答的字母。另一种可能性是对字母数组进行排序,并将其与原始字母进行比较。如果数组匹配,则它是您的场景中按字母顺序排列的单词,如果不匹配,则不匹配。

例如

foreach (var word in words)
{
var letters = word.ToList();
var sorted = word.OrderBy(l => l);
if (letters.SequenceEqual(sorted))
{
AlphabeticOrder.Add(word);
}  
}

哪个输出:

修道院,巨浪,寒战,abcde

逻辑存在缺陷
在前两个字母中满足条件,并立即添加到列表中。

List<string> AlphabeticOrder = new List<string>();
bool isOrdered = true; // Added this
foreach (var word in words)
{
isOrdered = true; // Added this
for (int i = 1; i < word.Length; i++)
{
if (word[i] < word[i - 1])
{
isOrdered = false; // Added this
break;
}
}

// Added this
if(isOrdered)
AlphabeticOrder.Add(word);
}

最新更新