在Ruby中循环遍历主集,处理每个子集的最简洁方法

时间:2011-02-13 17:05:43

标签: ruby loops records

这是一种常见的情况,我对这些解决方案并不满意。您有一组数据,在这种情况下,只假设按类别排序的数据库中的行。

您希望构建一个包含每个类别子集的缓冲区,并在每个类别更改时执行一些处理,然后清除缓冲区。假设process()包含在一堆你不想复制的复杂逻辑中

任何人都有更好的设置?

# category, city
data = [
          [10, 'citya'],
          [10, 'cityb'],
          [11, 'citya'],
          [11, 'cityb'],
          [11, 'citya'],
          [12, 'cityb'],
          [12, 'cityg']
       ]

# do some heavy lifting in here
def process(buf) p buf; end

cur_cat = nil
cur_cat_buf = []
data.each do |r|
  if r[0] != cur_cat
    cur_cat = r[0]
    process(cur_cat_buf) #<-- assume this is conditional, complex
    cur_cat_buf.clear
  end
  cur_cat_buf << r[1]
end
process(cur_cat_buf) #<-- assume the conditional is duplicated...ack.

这是另一种技术,而且非常糟糕。凌乱,太可怕了!总是向前看,检查它是否为零......等等......

cur_cat = data[0][0] if data.length > 0
cur_cat_buf = []
data.each_with_index do |r, i|
  cur_cat_buf << r[1]

  # look ahead
  if data[i+1] == nil or data[i+1][0] != cur_cat
    cur_cat = data[i+1][0] if data[i+1] != nil
    process(cur_cat_buf)
    cur_cat_buf.clear
  end
end

这是另一种选择。当然比上一个好。

cur_cat = nil
cur_cat_buf = []
for i in 0..(data.length)
  if (r = data[i]) == nil or r[0] != cur_cat
    process(cur_cat_buf)
    break unless r

    cur_cat_buf.clear
    cur_cat = r[0]
  end

  cur_cat_buf << r[1]
end

我想要一个干净,优雅的解决方案。必须有更好的方法!

2 个答案:

答案 0 :(得分:2)

data.group_by(&:first).each_value {|buffer| process(buffer.map &:last) }

答案 1 :(得分:1)

data.group_by(&:first).each_value do |pairs| 
  process(pairs.map(&:last)) 
end

或等效的,但稍微更详细,但更明确一点:

data.group_by { |category_id, city| category_id }.each_value do |pairs| 
  process(pairs.map { |category_id, cities| cities }) 
end