Как разделить и отсортировать массив в определенном порядке - PullRequest
0 голосов
/ 25 марта 2012

Введите

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 уникален.

Ожидаемый результат:

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 ]

1 голос
/ 26 марта 2012

Это должно сделать это (хотя это не очень красиво):

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 голос
/ 26 марта 2012

Вот другой подход.Я все еще не совсем доволен этим - не мог понять, как свести последние два шага в один.Также получилось больше строк, чем в ответе Эндрю Маршалла .Бу.

Спецификация прилагается.

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
0 голосов
/ 25 марта 2012

Простой ответ, вы можете использовать each_with_index, который работает аналогично each, но дает вам индекс, если цикл в качестве второго параметра.

Я не могу привести вам полный пример, к сожалению, какЯ не совсем понял ваш вариант использования.Однако с документацией вы сможете продолжить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...