优雅的Ruby一行代码

7

我喜欢使用Ruby编写代码的原因之一是它非常擅长通过一行代码实现很多功能。

我喜欢的包括:

@sentence = @sentence.split(' ').map!{|x| x = x[0..0].upcase << x[1..-1] }.join(' ')

它将每个单词的首字母大写,这并不是最惊人的,但相当有效。

你见过或编写过的最优雅的Ruby代码是什么?


2
请编辑并将其标记为社区wiki,以避免因为主观性(没有真正的答案)而被关闭 :) - Matchu
6
我不会称之为“优雅”,因为它几乎无法阅读。如果另一个程序员遇到这段代码,他们将不得不花费几分钟的时间来理解它的意图。它比优雅更加神秘。你以可读性为代价节省了按键操作。 - DOK
在你的例子中,为什么不使用 string.capitalize?虽然它可能做了更多的事情(它将字符串的其余部分转换为小写)。 - Matt Greer
@Matchu:你不能再将问题标记为社区维基了。它会自动发生。 (我不知道什么会阻止答案被关闭为过于主观。) - Ken Bloom
那么Ruby就是阿诺德·施瓦辛格会使用的编程语言? - Andrew Grimm
显示剩余3条评论
7个回答

29

您发布了这个一行代码:

@sentence = @sentence.split(' ').map!{|x| x = x[0..0].upcase << x[1..-1] }.join(' ')

但是你对 Ruby 存在一些误解。

首先,在 map 调用中使用 x= 不会影响 map 调用之外的任何内容。数组元素的新值是由块返回的值。

其次,你不需要使用 << 修改第一个字符串 -- 通过使用连接符 + 创建一个新字符串是更好的选择。

第三,map! 直接对 split 返回的数组进行更改。你要做的是保持该数组不变(即使它不改变程序语义),并通过使用 map 返回映射结果的新数组。

所以你应该写成:

@sentence = @sentence.split(' ').map{|x| x[0..0].upcase + x[1..-1] }.join(' ')

现在这个语句 x[0..0].upcase + x[1..-1] 非常晦涩难懂。或许你可以使用 capitalize 方法来替换它,该方法已经将字符串的第一个字母改为大写。(请注意,它还会将所有其他字母转换为小写,这可能是你想要的,也可能不是。)

@sentence = @sentence.split(' ').map{|x| x.capitalize }.join(' ')

我可能会使用 gsub! 来原地修改字符串的某些部分,但这可能有点晦涩难懂:

@sentence.gsub!(/\S+/){|x| x.capitalize}

还有一件事。如果块的唯一目的是在传递给该块的对象上调用单个方法,则可以执行以下操作:

@sentence = @sentence.split(' ').map(&:capitalize).join(' ')

或者修改我的gsub!版本:

@sentence.gsub!(/\S+/,&:capitalize)

13
刚才,你要么完全打击了他的精神,要么他已经把对一句话的热情翻了两番。 - Stéphan Kochen
我希望能从这里的回复中学到很多东西,而Ken的评论已经成为了一次完美的教育之旅!绝对让人兴奋地三倍了那个一行代码! - kez
3
+1 @sentence = @sentence.split(' ').map(&:capitalize).join(' ') 这句话非常优雅。 - the Tin Man
1
@CravingSpirit::something 是一个符号,代表函数的名称。& 通过在符号上调用 to_proc 将其转换为 Proc。当您在符号上调用 to_proc 时,它会创建一个函数,该函数调用其第一个参数中具有该名称的方法。(因此,:capitalize.to_proc() 创建一个 lambda foo,当您调用 foo(a) 时,它会调用 a.capitalize - Ken Bloom

1

1

在一行代码中打开一个文件,写入内容并关闭它:

File.open(File.join(Rails.root, 'lib', 'assets', 'file.txt'), 'a+') {|f| f.write("stuff"+"\n" }

我在日常脚本中使用大量的 Ruby 一行代码,其中包括 andunlessif&& 等等:

puts "x is nil!" if x.nil?

您可以交替使用unlessif,但是当正确使用时,unless显着提高了可读性:

puts "bad input type!" unless ["bs", "cf", "is"].include?(type)

往往情况下,最好的Ruby一行代码最终是由两到三行的一行代码共同完成的,通常与Ruby的变量“价值”系统(nilfalse是唯一的“负面”)相结合:
def try_first(actual_index)
    x = [get_header(actual_index, 0), get_data(actual_index, 0)] unless get_header(actual_index, 0).blank?
    x = try_second(actual_index) if x[0].blank? #blank is a rails method, detects nil and empty strings and empty containers ([]) I think too
    puts "x is nil!" if x.nil?
    x
end

我使用由几个一行代码组成的单行代码来表达我的意思,因为这种方法本身在我的代码中并不是最简洁的。虽然我的许多方法只有一行代码:

def get_all_coords(type)
  eval("@#{type}_coords")
end

这就是你真正开始优雅的方式。将代码拆分为单独的方法。一行代码的方法是完美的。


1

肯定是斐波那契数列!

def fib(n, t = n < 2 ? n : fib(n-1) + fib(n-2)) t; end

0

绝对是GREP的仿真(Windows用户)。[鸣谢Dave Thomas]

ruby -pe 'next unless $_ =~ /regexp/' < file.txt

0

嗯,我几天前写了一个,但由于那时问题已关闭,所以无法将其用作答案。 如果该字符串不存在,则将文件的第一行替换为字符串。

我希望有人也能改进这个:

ruby -i.bak -pe "print ($_!~/string/ && $.<2) ? \"string\n\":''" filename.txt

0

斐波那契数列生成器:

def fib n;n==0?[0]:n==1?[0,1]:(2..n-1).inject([0,1]){|a|a<<(a[-1]+a[-2])};end

同上:

def fib n;n<2?(0..n-1).to_a():(2..n-1).inject([0,1]){|a|a<<(a[-1]+a[-2])};end

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