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