Ruby 如何仅用 each 实现 each_slice 的功能?

shaunli · 2015年03月07日 · 最后由 zyjloveher 回复于 2015年03月09日 · 3059 次阅读

选自《七周七语言》的 Ruby 部分:

有一个数组,包含 16 个数字。仅用 each 方法打印数组中的内容,一次打印 4 个数字。然后,用可枚举模块的 each_slice 方法重做一遍

我想问如何仅用 each 实现 each_slice 的功能?我的想法很丑陋:

sequence = (1..16)
buffer = []
count = 0
sequence.each do |e|
  buffer << e
  if buffer.size >= 4
    p buffer
    buffer = []
  end
end

有没有更好的方法呢?

楼主这个是有问题的,如果把 16 改成 15:

sequence = (1..15)
buffer = []
count = 0
sequence.each do |e|
  buffer << e
  if buffer.size >= 4
    p buffer
    buffer = []
  end
end
# 输出
# [1, 2, 3, 4]
# [5, 6, 7, 8]
# [9, 10, 11, 12]

后面三个没有打出来

我写了一个,但是感觉比较丑陋:

module Enumerable
  def i_each_slice(n, &block)
    raise "invalid slice size" if n <= 0

    i, ary = 0, []

    each do |a|
      ary << a
      i += 1
      if i >= n
        yield ary
        i, ary = 0, []
      end
    end

    yield ary if i > 0
  end
end

(1..10).i_each_slice(3) { |a| p a }

# 输出
# [1, 2, 3]
# [4, 5, 6]
# [7, 8, 9]
# [10]

期待大神们更优雅的解法。

#2 楼 @chiangdi 谢谢~比我的好多了:P

module Enumerable
  def i_each_slice(n)
    raise "invalid slice size" if n <= 0

    result, i = [], 1

    self.each do |ele|
      index = (i / n.to_f).ceil
      result[index].nil? ? result[index] = [ele] : result[index] << ele
      i += 1
    end

    result[1..-1].each { |ele| yield ele }
  end
end

['a', 'b', 'c', 'd', 'e', 1, 2, 3, 4, 5].i_each_slice(3) { |i| p i }
# =>
# ["a", "b", "c"]
# ["d", "e", 1]
# [2, 3, 4]
# [5]

还可以再短点不过就要略微影响可读性了

@blacktulip 的解法估计会吓退不少 ruby 初学者 这个不过是个入门级的题,我补充个杀鸡刀版吧

i = 0
(1..16).to_a.each do |n|
  i += 1
  print i % 4 == 0 ? "#{n}\n" : "#{n},"
end
(0..3).each do |a|
    arr = []
    (1..4).each do |b|
        arr << a * 4 + b
    end
    puts arr.to_s
end
(1..16).to_a.each_with_index { |n, i| print "#{n}#{(i+1)%4==0 ? "\n" : ","}" }

Only use each here:

(array = (1..16).to_a).each { |n| print "#{n}#{(array.index(n)+1)%4==0 ? "\n" : ","}" }

#10 楼 @blacktulip 粗略的浏览,my bad

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