使用 #inject 将字符串从数组中连接起来

11

我正在学习在线课程,通常需要一个非常简单的一行代码解决问题。现在有这样一个问题,给定以下数组:

["emperor", "joshua", "abraham", "norton"]

我必须使用#inject函数来获取所有名字拼接成的一个字符串,每个名字的首字母大写,并用指定字符串分隔开,就像这样:

"Emperor Joshua Abraham Norton"

虽然使用 #map#join 可以很容易地完成此操作,但这个具体的练习只需要使用 #inject。我想到了以下的方法:

["emperor", "joshua", "abraham", "norton"].inject("") do |memo, word|
   memo << word.capitalize << " "
end

这会给我:

"Emperor Joshua Abraham Norton "

如何在不包含字符串末尾空格的情况下实现此目标?

  • 我如何在不包含末尾空格的情况下实现这一点?
  • 传递空字符串是否是使用 #inject 的正确方法?
  • 我是否正确使用 << 来组合字符串?

1
良好而详细地描述问题,适合初学者。 - megas
感谢所有的答案!我知道在这种情况下使用#inject似乎很愚蠢,但这只是其中一个旨在测试您对概念理解而不一定是寻找最短和最有效解决方案能力的练习。 - Darek Rossman
6个回答

10

试试这个:

a.map{|t| t.capitalize}.join(" ")

我认为使用注入无法避免额外的空格。同时,您需要进行以下操作:

memo = memo + word.capitalize + " " 

编辑:由于声明已更改为禁止使用join和map,因此这里提供了一种稍微丑陋的解决方案,即使用inject:

a.inject("") do |memo, world|
  memo << " " unless memo.empty?
  memo << word.capitalize
end

谢谢!练习要求我使用 #inject 提供解决方案,并且不得使用 #map 和 #join。我已经更新了我的原始问题来说明这一点。 - Darek Rossman
搞定了!另一位海报使用了unless memo.empty?,也起作用了。谢谢! - Darek Rossman
我已经改进了我的答案,多亏了user1252434的帮助,使用unless和empty使代码更像Ruby风格。请再仔细看一下。 - Ivaylo Strandjev
1
为了提高性能,最好使用<<而不是+=。前者的时间复杂度为O(n),而后者的时间复杂度为O(n^2) - Marc-André Lafortune
这篇文章非常有价值,我希望能将它添加到我的收藏夹列表中。 - Donato
显示剩余2条评论

2
a = ["emperor", "joshua", "abraham", "norton"]
a.drop(1).inject(a.first.capitalize){|res,m| res << ' '+m.capitalize }

谢谢您的回复!我编辑了我的原始问题,以澄清这个练习需要使用#inject。它明确表示不要使用#map和#join。 - Darek Rossman
哦,那很有趣...谢谢!你能解释一下在 res 后面使用 << 和在 m.capitalize 前面使用 + 的用法吗?在这种情况下两者之间有区别吗? - Darek Rossman
1
'+m.capitalize' 将返回 " Joshua" 并添加到初始值 "Emperor"。操作的结果将是 "Emperor Joshua",这将传递到下一次迭代。 - megas
接近了,但第一个元素被加了两次。代码的结果是“皇帝皇帝约书亚·亚伯拉罕·诺顿”。如果在a[1..-1]上调用inject应该可以解决这个问题。 - user1252434

1

有比 #inject 更好的方法,可以看看其他答案。但如果你坚持,你可以只需将尾随空格字符 String#rstrip

或者将块反转,并在添加字符之前检查 memo 是否为空。

memo << " " unless memo.empty?
memo << name.capitalize

我不确定 << 运算符。我会使用 +,但那可能只是个人偏好。


1

检查每次加入" "比上一次输出chop!更昂贵。关于<<的选择通常是正确的,你可以查看字符串连接

%w(emperor joshua abraham norton).inject("") do |m,w|
  m << w.capitalize << " "
end.chop!
"Emperor Joshua Abraham Norton"

啊,非常好,谢谢!我还有很多方法需要学习。 - Darek Rossman

0

不要使用#inject,有更好的解决方法:

["emperor", "joshua", "abraham", "norton"].map(&:capitalize).join(' ')

你的第一个目标应该是解决手头的问题。你可以使用#inject,但这并不是最理想的或明显的解决方案。你有更好的事情可做,而不是试图弄清楚如何欺骗#inject来给你正确的结果。


我建议您在Code Golf SE上提出这个问题,看看人们会想出什么。 - wersimmon
问题陈述说,虽然可以(而且应该)使用 #map 和 #join 轻松完成,但它希望你使用 #inject。这个练习旨在让你了解这些方法的作用和工作原理。 - Darek Rossman
那么,用一个有意义的问题来测试你的理解力吧:比如“将1到100之间所有数字相加,但减去可被5整除的数字”。 - wersimmon

0

puts x.inject { |memo, val| "#{memo} #{val.upcase}" }


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