您被邀请到每个字母“映射”到另一个字母,那么你将要使用的方法Enumerable#map。
VOWELS = "aeiou"
letters = ('a'..'z').to_a
#=> ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
"n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
letters.map do |c|
<code referencing c>
end
#=> ['b', 'c', 'd', 'E', 'f',..., 'z', 'A]
现在,让我们填写的代码,使用方法:
- String#succ,其中,由于一个字符,返回与下一个更高的ASCII值的字符。例如,
"b".ord #=> 98
,因此"b".sucC#=> "c"
,因为"c".ord #=> 99
。由于"z".sucC#=> 'aa'
,我们需要将“z”作为特例。 String#succ
与String#next相同。
- String#include?String#include?,给定字符串,返回
true
或false
,具体取决于接收器中是否包含include?
的参数(字符串)。例如,"cat".include?("at") #=> true; "cat".include?("a") #=> true; "cat".include?("z") #=> false
。请注意,VOWELS
,因为它以大写字母开头,是一个常数。
- String#upcase,它将给定字符串中的所有小写字母转换为大写字母(并保留所有其他字符不变)。
letters.map do |c|
if c == 'z'
'A'
else
s = c.succ
if VOWELS.include?(s)
s.upcase
else
s
end
end
end
#=> ["b", "c", "d", "E", "f", "g", "h", "I", "j", "k", "l", "m", "n",
# "O", "p", "q", "r", "s", "t", "U", "v", "w", "x", "y", "z", "A"]
此使用case
声明和Ruby的ternary operator你可以代替写:
letters.map do |c|
case c
when 'z'
'A'
else
s = c.succ
VOWELS.include?(s) ? s.upcase : s
end
end
,或者你可以利用的方法String#ord和Integer#chr:
letters.map do |c|
s = ('a'.ord + ((c.ord-'a'.ord+1) % 26)).chr
VOWELS.include?(s) ? s.upcase : s
end
end
如果,例如,c = 'r'
('a'.ord + ((c.ord-'a'.ord+1) % 26).chr
#=> (97 + ((114-97+1) % 26).chr
#=> (97 + 18 % 26).chr
#=> (97 + 18).chr
#=> 115.chr
#=> 's'
但是,如果c = 'z'
('a'.ord + ((c.ord-'a'.ord+1) % 26).chr
#=> (97 + ((122-97+1) % 26).chr
#=> (97 + 26 % 26).chr
#=> (97 + 0).chr
#=> 97.chr
#=> 'a'
另一种方式。 (你可以找出为什么这个工作。)
letters.map do |c|
s = c.succ[0]
VOWELS.include?(s) ? s.upcase : s
end
你可能反而希望创建一个散列。
letter_mapping = {}
letters.each do |c|
s = c.succ[0]
letter_mapping[c] = VOWELS.include?(s) ? s.upcase : s
end
letter_mapping
#=> { "a"=>"b", "b"=>"c", "c"=>"d", "d"=>"E", "e"=>"f", "f"=>"g", "g"=>"h",
# "h"=>"I", "i"=>"j", "j"=>"k", "k"=>"l", "l"=>"m", "m"=>"n", "n"=>"O",
# "o"=>"p", "p"=>"q", "q"=>"r", "r"=>"s", "s"=>"t", "t"=>"U", "u"=>"v",
# "v"=>"w", "w"=>"x", "x"=>"y", "y"=>"z", "z"=>"A"}
因此,例如,letter_mapping['r'] #=> "s"
。
随着时间的推移,你会发现,写这个的Ruby的方法是:
letters.each_with_object({}) do |c, letter_mapping|
s = c.succ[0]
letter_mapping[c] = VOWELS.include?(s) ? s.upcase : s
end
#=> { "a"=>"b", ... "z"=>"A"}
最后一件事。 Enumerable#map
是包含Enumerable
模块的每个类的实例方法。其中一类是Array
:
Array.included_modules
#=> [Enumerable, Kernel]
Array.instance_methods.include?(:map)
#=> true
Array
具有使用模块的所有Enumerable
的方法,就好像他们在Array
定义。这就是为什么当map
接收器是一个数组时。
另一类包括Enumerable
是Range:
Range.included_modules
#=> [Enumerable, Kernel]
Range.instance_methods.include?(:map)
#=> true
因此,与其写:
letters = ('a'..'z').to_a
我们可以(应该)写:
letters = ('a'..'z')
以及上述所有代码将工作得很好。
jtbandes你是怎么把我的答案放在一个漂亮的灰色方形那样的? –
欢迎来到Stack Overflow。请阅读“[问]”和链接页面,以及“[mcve]”。我们期望获得更多信息:描述您期望的输出结果,以及目前的结果。你遇到了什么问题?你的代码在语法上不正确,所以你应该先处理它。一旦你的代码被Ruby解释器接受为语法上正确的话,那么你将会在一个更好的地方提出一个问题。 –
*为什么*你想避免使用'find'和'sort'?重塑经过充分测试和优化的车轮?虽然这是一个好主意,但当你第一次学习编程时是不实际的。了解算法是非常有用的,但我建议学习使用现有的工具,并且随着时间的推移,您将了解如何构建这些算法,并尝试构建自己的算法。然而,*始终*要注意,需要使用现有的车轮/方法/功能代码,因为它已经过多年的编写和优化,可以解决您不会预料到的问题。 –