Ruby 请教一个 each_with_object / inject /tap 相关 更优雅的写法

mingyuan0715 · 2018年05月17日 · 最后由 msg7086 回复于 2018年05月24日 · 637 次阅读

有数组 [2,1,4,3], 希望得到 [ "2", "2/1", "2/1/4", "2/1/4/3"]

实现了个版本,觉得不够优雅。

[1,2,3,4].each_with_object([]) {|i, x| x << [x.last, i].compact.join('/') }

# =>
[ "1", "1/2", "1/2/3",  "1/2/3/4"]

有更好的实现方法么~

共收到 17 条回复

[1,2,3,4].map {|i| (1..i).to_a.join("/")}

caicai,我这个怎么样。

[2, 1, 4, 3].map.with_index {|i,index| a[0,index+1].join("/")}

rubyonlinux 回复

数组元素 不一定有规律呢

mingyuan0715 回复

应该是这样 [2, 1, 4, 3].map.with_index {|i,index| a[0,index+1].join("/")}

rubyonlinux 回复

这个不错,学到了,谢谢啦~

[1,2,3,4].inject {|i, x| [i, x].join('/').tap { |i| puts i } }

1/2
1/2/3
1/2/3/4
=> "1/2/3/4"

我第一想到的是inject,但是我没有好的思路输出成数组。

拆数组的时候根本没有用到数组元素

(0..a.size-1).map { |index| a[0,index+1].join("/")}
lyb124553153 回复

先 -1 再 +1 何必呢 😂

(1..a.size).map { |index| a[0,index].join("/") }

# 我再来一个变种
a.map.with_index(1) { |_, i| a.first(i).join('/') }
1.upto(a.size).map{|i| a.take(i).join '/' }

这是病,得治😅

luikore 回复

真要为了优雅不计成本了呀?!

本来一次循环搞定的事要不要这么费劲?

str_arr = []
str = ''
arr.each {|e| str == '' ? str = "#{e}" : str = "#{str}/#{e}"; str_arr << str }
gihnius 回复

我觉得成本要综合来看, 有读代码成本(是否优雅); 内存成本(如变量的数量); CPU成本(如迭代次数); 最终做个权衡。

IChou 回复

😀 -1 以后就和下标一样了 读起来更容易懂

只贴代码不说话,怕被打 ^_^

# 两行版
arr = [1, 2, 3, 4]

# 通俗易懂版
0.upto(arr.size - 1).collect { |len| arr[0..len].join('/') }
# => ["1", "1/2", "1/2/3", "1/2/3/4"]

# 需自行看Array#new代码版
Array.new(arr.size) { |len| arr[0..len].join('/') }
# => ["1", "1/2", "1/2/3", "1/2/3/4"]
# 单行版, 仅限ruby 2.5.0以上
[1, 2, 3, 4].yield_self { |arr| Array.new(arr.size) { |len| arr[0..len].join('/') } }
# => ["1", "1/2", "1/2/3", "1/2/3/4"]
zfjoy520 回复
0.upto(arr.size - 1)

->

arr.size.times
msg7086 回复

rubocop其实是不建议用 x.times.map / x.times.collect 这种用法的,可以看这里:

https://github.com/bbatsov/rubocop/blob/master/lib/rubocop/cop/performance/times_map.rb

会有这样的提示出现: Use Array.new with a block instead of .times.collect.

写 0.upto(arr.size - 1) 纯粹是为了容易看懂,一般情况下,都是用 Array.new(arr.size)

zfjoy520 回复

只说了结论,没有说原因,看上去也就是省掉了一个Enumerator的初始化,我不觉得是什么严重的性能问题。

而且写代码本来可读性就是很重要的,我觉得x.times.map读起来比Array.new(x)更直观一些。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册