如何使用lambda解决这个问题

3

这是问题:

“编写一个程序,从文本中提取所有回文单词,例如ABBA、lamal、exe。”

以下是我的代码:

public static List<string> FindPalindromes()
    {
        string text = String.Empty;
        Console.Write("Enter the text:\n\t");
        text = Console.ReadLine();

        List<string> answer = new List<string>();

        string[] words = text.Split('.', ',', ' ', ':', '/', '\\', '"', ';');
        foreach(string word in words.Where(
                (string x) =>
                {
                    if(String.Equals(x, x.Reverse()))
                        return true;
                    else
                        return false;
                }
            ))
            answer.Add(word);

        return answer;
    }

现在我认为如果我将where方法中的逻辑分离成一个单独的方法,返回一个布尔值并检查单个单词是否是回文会更加整洁。但我想尝试使用lambda表达式。

无论如何,这段代码没有返回任何东西。我怀疑问题出在if条件语句中。


2
你可以将Lambda表达式简化为x => String.Equals(x, x.Reverse()) - clcto
5个回答

6

x.Reverse() 调用的是 Enumerable.Reverse(),它将返回一个 IEnumerable<char> 类型的集合 - 而不是字符串。这就是为什么 Equals 没有返回 true 的原因。以下是一种替代方法:

char[] chars = x.ToCharArray();
Array.Reverse(chars);
return x == new string(chars);

或者您可以在字符序列的反转上调用string.Joinstring.Concat - 这种方法效率极低,但它将在一个表达式中完成工作,允许您将从foreach开始的所有内容替换为:

return words.Where(x => x == string.Concat(x.Reverse())
            .ToList();

更加简洁 :) 每当你发现自己不断向列表中添加元素时,考虑使用查询和 ToList()。你已经完成了筛选部分,只需要使用 ToList() 来消除 foreach 循环即可。

同样地,每当你发现自己有以下情况:

if (condition)
    return true;
else
    return false;

我强烈建议进行重构,以便更好地适应IT技术。

return condition;

string.Concat(x.Reverse())Join 更加简洁 ;) - digEmAll
完全没有关系,但我倾向于使用string.Empty而不是""。现在看到你使用""让我想知道是否应该因为羞耻和彻底失败而永远放弃编程。 - Federico Berasategui
""string.Empty 是相同的。这只是个人偏好的问题。 - recursive
1
@recursive: 几乎相同。 "" 是编译时常量;string.Empty 不是。关于这个问题有一个帖子... - Jon Skeet

3

是的,问题出在你的 String.Equals 调用上。 x.Reverse 返回的是一个 IEnumerable<char>,这个对象永远不会等于你的字符串。可以尝试以下代码:

if(String.Equals(x, new string(x.Reverse().ToArray()))

“new string” 没有接受 “IEnumerable<char>” 的重载。 - EZI

2
您的代码可以改为以下内容:
answer = words.Where(x => String.Join("", x.Reverse()) == x).ToList();

@Servy:String.Join在.NET 4中增加了新的重载。http://msdn.microsoft.com/zh-cn/library/system.string.join(v=vs.100).aspx - Jon Skeet
嗯,它没有使用那个重载... 它正在使用 Join<T>(String, IEnumerable<T>) - Jon Skeet
@JonSkeet 对,当时我在错误的机器上。不过,它并不是这项工作的合适工具。 - Servy
1
我会使用string.Concat而不是带有空分隔符的string.Join - recursive
@recursive 当然,这里使用Join没有任何意义。 - Sergey Berezovskiy
@SergeyBerezovskiy,你真是太好了,感谢你编辑我的大约25个答案。 - EZI

1

x.Reverse 不是字符串,它是一个 IEnumerable<char>。你需要将这个字符序列转换回字符串,以便与另一个字符串进行比较。或者使用一个可以比较两个序列而不是两个字符串的比较工具,因为你没有一个字符串:

return words.Where(word => word.SequenceEqual(word.Reverse()))
    .ToList();

1
我会这样重写它:

我会这样重写它:

public static List<string> FindPalindromes() {
    Console.Write("Enter the text:\n\t");
    string text = Console.ReadLine();
    string[] words = text.Split('.', ',', ' ', ':', '/', '\\', '"', ';');

    return words.Where(word => word.Reverse().SequenceEqual(word)).ToList();
}

这会带来一些变化。
  1. 它不使用中间的List来存储结果。这在linq中是不必要的。
  2. 它不使用if语句。因为if条件中已经有一个值,它的唯一目的是返回true或false。
  3. 它修正了反向比较。它使用.SequenceEqual正确比较两个序列中的字符。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接