如何按定义的顺序对数组进行分类和排序

时间:2012-03-25 16:47:55

标签: ruby algorithm

输入

cycle = 4
order = []
order[0] = [
  /foobar/, /vim/
]
order[1] = [ /simple/,/word/, /.*/ ]
record = [ 'vim', 'foobar', 'foo', 'word', 'bar', 'something', 'something1', 'something2', 'something3', 'something4']

要求

我想制作一个名为report的列表。原始来源是record,它是一维数组。 record的所有元素将被拆分为不同的组并进行排序。组和顺序在order中定义。

这是伪代码:

order.each do |group|
  group.each do |pattern|
    record.each do |r|
      if r =~ pattern
        @report[# of group][# of  row][ # of element (max is 4th)] = r 
      end
    end
  end    
end

请注意:

  1. [row]中的元素编号为4,在cycle中定义。
  2. [# of row]:如果# of element> 4,# of row将+ 1
  3. report中的每个元素(字符串)都是唯一的。
  4. 预期输出:

    require 'ap'
    ap report
    
     [
        [0] [
            [0] [
                [0] "foobar",
                [1] "vim"
            ]
        ],
        [1] [
            [0] [
                [0] "word",
                [1] "foo",
                [2] "bar",
                [3] "something"
            ],
            [1] [
                [0] "something1",
                [1] "something2"               
                [2] "something3"
                [3] "something4"
    
            ]
        ]
    ]
    

3 个答案:

答案 0 :(得分:1)

这应该这样做(虽然它不是很漂亮):

report = []
record.uniq!
order.each_with_index do |group, gi|
  group.each do |pattern|
    record.select { |r| r =~ pattern }.each do |match|
      report[gi] ||= [[]]
      report[gi] << [] if report[gi].last.length == cycle
      report[gi].last << match
    end
    record.delete_if { |r| r =~ pattern }
  end
end

puts report.inspect
#=> [[["foobar", "vim"]], [["word", "foo", "bar", "something"], ["something1", "something2", "something3", "something4"]]]

请注意,record已发生变异,因此如果您需要保持不变,则应该dup

答案 1 :(得分:1)

这是另一种方法。我仍然对此并不完全满意 - 无法弄清楚如何将最后两步归为一体。此外,它的行数比Andrew Marshall's更多。嘘声。

规格附件。

require 'spec_helper'

def report(cycle, order, record)
  record.uniq!
  order.each_with_index.map do |pattern_list, index|
    pattern_list.map do |pattern|
      record.each_with_index.inject([]) do |memo, (item, item_index)|
        memo.tap do
          if pattern =~ item
            memo << item
            record[item_index] = nil
          end
        end
      end
    end.flatten
  end.map do |items|
    items.each_with_index.group_by do |item, index|
      index.div(cycle)
    end.map do |ordering, item_with_index|
      item_with_index.map(&:first)
    end
  end
end

describe 'report' do
  let(:cycle) { 4 }
  let(:order) { [
    [/foobar/, /vim/],
    [/simple/,/word/, /.*/]
  ] }
  let(:record) {
    [ 'vim', 'foobar', 'foo', 'word', 'bar', 'something', 'something1', 'something2', 'something3', 'something4']
  }

  it "just works" do
    report(cycle, order, record.dup).should == [
      [["foobar","vim"]],
      [["word","foo","bar","something"],["something1","something2","something3","something4"]]
    ]
  end
end

答案 2 :(得分:0)

简单回答,您可以使用与each_with_index类似的each,但如果将循环作为第二个参数,则为您提供索引。

我不能遗憾地给你一个完整的例子,因为我没有完全理解你的用例。但是使用documentation,您应该可以继续。