如何结合两个红宝石集合



给出了两个输入,AB(集合(和一个数字X,并且必须创建输出。输出始于A的第一个值,然后从B中获得X单元,然后从A的第二个值中获取,然后继续进行此操作,直到AB都用尽。您可以假设1 < X < sizeof(B)。但是,如果AB用完了,则应循环回到简短集合的开头,然后继续直到另一个算完为止。循环后退应继续,直到两个收藏都达到了终点为止。

在Ruby中进行此操作的优雅是什么?我有一些半破碎的代码,似乎找不到这样做的好方法。不,这不是作业问题。我有奇怪的爱好。

这是我想要的行为的一些示例测试:

# SomeModule.copy(A, B, X)
SomeModule.copy(%w(a1 a2 a3),    %w(b1 b2 b3),       1) == %w(a1 b1 a2 b2 a3 b3))
SomeModule.copy(%w(a1),          %w(b1),             1) == %w(a1 b1))
SomeModule.copy(%w(a1),          %w(b1 b2 b3),       1) == %w(a1 b1 a1 b2 a1 b3))
SomeModule.copy(%w(a1 a2),       %w(b1 b2 b3 b4 b5), 2) == %w(a1 b1 b2 a2 b3 b4 a1 b5 b1))
SomeModule.copy(%w(a1 a2),       %w(b1 b2 b3 b4 b5), 2) == %w(a1 b1 b2 a2 b3 b4 a1 b5 b1))
SomeModule.copy(%w(a1 a2 a3 a4), %w(b1 b2 b3 b4 b5), 3) == %w(a1 b1 b2 b3 a2 b4 b5 b1 a3 b2 b3 b4 a4 b5 b1 b2))

这是某种内容,这个想法是要迭代每个数组,直到它们都达到最大索引:

def custom_combine(a,b,x)
  max_index_a = a.count - 1
  max_index_b = b.count - 1
  a_run_out = false
  b_run_out = false
  output = []
  a.cycle.each_with_index do |elem_a, index_a|
    output << elem_a
    # base on a index get x elements from b
    x.times do |i|
      index_b = ((index_a * x) + i) % (max_index_b + 1)
      output << b[index_b]
      b_run_out = true if index_b == max_index_b
    end
    a_run_out = true if index_a == max_index_a
    break if a_run_out && b_run_out
  end
  output
end
a = %w(a1 a2 a3 a4)
b = %w(b1 b2 b3 b4 b5)
x = 3
custom_combine(a,b,x)
# => ["a1", "b1", "b2", "b3", "a2", "b4", "b5", "b1", "a3", "b2", "b3", "b4", "a4", "b5", "b1", "b2"] 

Enumerable具有each_slice方法,该方法可让您一次通过枚举的对象n个项目迭代。使用它,您可以做这样的事情:

a1 = [1, 2, 3, 4, 5, 6] 
a2 = [10, 11, 12, 20, 21, 22, 30, 31, 32, 40, 41, 42, 50, 51, 52, 60] 
a1.each_slice(1).zip(a2.each_slice(3)).flatten
# => [1, 10, 11, 12, 2, 20, 21, 22, 3, 30, 31, 32, 4, 40, 41, 42, 5, 50, 51, 52, 6, 60] 

这是终于在4.30am跳出我的大脑:

class InfiniteArray
  private
  attr_reader :collection
  attr_accessor :index, :wrapped_count
  public
  def initialize(collection)
    @collection = collection
    reset
  end
  def next
    value = collection[index]
    if index < collection.length - 1
      self.index = index + 1
    else
      self.index = 0
      self.wrapped_count = wrapped_count + 1
    end
    value
  end
  def wrapped?
    wrapped_count > 0
  end
  def reset
    @index = 0
    @wrapped_count = 0
  end
end
class IntervalCopier
  private
  attr_reader :source_collection, :destination_collection, :interval
  public
  def initialize(source_collection, destination_collection, interval)
    @source_collection = InfiniteArray.new(source_collection)
    @destination_collection = InfiniteArray.new(destination_collection)
    @interval = interval
  end
  def copy
    final = []
    until source_collection.wrapped? && destination_collection.wrapped? do
      final << source_collection.next
      interval.times { final << destination_collection.next }
    end
    [source_collection, destination_collection].each(&:reset)
    final
  end
end
def copy(array1, array2, slice_length)
  iterations = [array1.length,
                (array2.length.to_f / slice_length.to_f).round
               ].max
  result = []
  enum1 = array1.cycle
  enum2 = array2.cycle
  iterations.times do
    result << enum1.next
    slice_length.times { result << enum2.next }
  end
  result
end
require 'minitest/autorun'
class TestCopy < Minitest::Test
  def test_copy
    assert_equal(%w(a1 b1 a2 b2 a3 b3),                               copy(%w(a1 a2 a3),    %w(b1 b2 b3),       1))
    assert_equal(%w(a1 b1),                                           copy(%w(a1),          %w(b1),             1))
    assert_equal(%w(a1 b1 a1 b2 a1 b3),                               copy(%w(a1),          %w(b1 b2 b3),       1))
    assert_equal(%w(a1 b1 b2 a2 b3 b4 a1 b5 b1),                      copy(%w(a1 a2),       %w(b1 b2 b3 b4 b5), 2))
    assert_equal(%w(a1 b1 b2 a2 b3 b4 a1 b5 b1),                      copy(%w(a1 a2),       %w(b1 b2 b3 b4 b5), 2))
    assert_equal(%w(a1 b1 b2 b3 a2 b4 b5 b1 a3 b2 b3 b4 a4 b5 b1 b2), copy(%w(a1 a2 a3 a4), %w(b1 b2 b3 b4 b5), 3))
  end
end

最新更新