如何解决按子数组总大小将子数组拆分为Ruby
我有一个子数组数组:
arr = [["a","b","c"],["a","b"],["c","v"],"f"],["e","a"],"n","m"],"c","g"]]
我想将每个子数组的元素放到另一个数组中,但是子数组的总和必须小于或等于6。所以我想得到类似这样的东西
[["a","a","v","f","e","m","g"]]
我现在的代码是
stop = 0
new_arr = []
indexo = ""
arr.each_with_index do |x,index|
stop = stop + x.size
if stop <= 6
new_arr << x
indexo = index
end
end
我被困在这里,因为我的代码仅包含两个前元素。原始数组大约有1000个子数组,而我的代码并未将其拆分为这种形式。
解决方法
您可以使用reduce方法并继续将子数组推入新数组。请考虑以下内容:
new_arr = arr.reduce([]) do |acc,sub_array|
last_element = acc[acc.length - 1]
if last_element.nil? or (last_element + sub_array).length > 6
acc << sub_array
else
acc[acc.length - 1] = last_element + sub_array
end
acc
end
# Tests
new_arr.flatten.size == arr.flatten.size # test total number of elements in both the arrays
new_arr.map(&:size) # the sizes of all sub arrays
new_arr.map(&:size).min # min size of all sub arrays
new_arr.map(&:size).max # max size of all sub arrays
让我知道代码是否不清楚
更新:
Reduce方法将通过遍历可枚举的每个元素来将任何可枚举的对象“还原”为单个值,就像each
,map
考虑一个例子:
# Find the sum of array
arr = [1,2,3]
# Reduce will accept an initial value & a block with two arguments
# initial_value: is used to set the value of the accumulator in the first loop
# Block Arguments:
# accumulator: accumulates data through the loop and finally returned by :reduce
# value: each item of the above array in every loop(just like :each)
arr.reduce(0) do |acc,value|
# initial value is 0; in the first loop acc's value will be set to 0
# henceforth acc's value will be what is returned from the block in every loop
acc += value
acc # acc is begin returned; in the second loop the value of acc will be (0 + 1)
end
因此,在这种情况下,在每个循环中,我们将该项的值添加到累加器中,并返回累加器以在下一个循环中使用。一旦reduce迭代了数组中的所有项目,它将返回累加器。
Ruby还提供了语法糖以使其看起来更漂亮:
arr.reduce(:+) # return 6
很好article,以供进一步参考
因此,如果您以问题为例:
# Initial value is set to an empty array,what we're passing to reduce
new_arr = arr.reduce([]) do |acc,sub_array|
# In the first loop acc's value will be set to []
# we're finding the last element of acc (in first loop since the array is empty
# last element will be nil)
last_element = acc[acc.length - 1]
# If last_element is nil(in first loop) we push the first item of the array to acc
# If last_element is found(pushed in the previous loops),we take it and sum
# it with the item from the current loop and see the size,if size is more
# than 6,we only push the item from current loop
if last_element.nil? or (last_element + sub_array).length > 6
acc << sub_array
else
# If last element is present & last_element + item from current loop's size
# is less than 6,we push the (last_element + item from current loop) into
# the accumulator.
acc[acc.length - 1] = last_element + sub_array
end
# Finally we return the accumulator,which will be used in the next loop
# Or if has looped through the entire array,it will be used to return back
# from where it was called
acc
end
,
arr = [["a","b","c"],["a","b"],["c","v"],"f"],["e","a"],"n","m"],"c","g"]]
arr.each_with_object([[]]) do |a,ar|
if a.size + ar[-1].size > 6
ar << a
else
ar[-1] += a
end
end
#=> [["a","a",# ["c","v","f","e",# ["a","m","g"]]
步骤如下。
enum = arr.each_with_object([[]])
#=> #<Enumerator: [["a",...
# ["a","g"]]:each_with_object([[]])>
第一个值是由该枚举数生成的,并传递到块中,并且通过将Array Decomposition应用于传递到该块的两元素数组来为块值分配值。
a,ar = enum.next
#=> [["a",[[]]]
a #=> ["a","c"]
ar #=> [[]]
请参见Enumerator#next。然后评估条件语句。
a.size + ar[-1].size > 6
#=> 3 + 0 > 6 => false
所以我们执行:
ar[-1] += a
#=> ["a","c"]
ar #=> [["a","c"]]
下一个元素由enum
生成,传递到块,并为块值分配值。
a,[["a","c"]]]
a #=> ["a","b"]
ar #=> [["a","c"]]
条件语句被评估。
a.size + ar[-1].size > 6
#=> 2 + 3 > 6 => false
所以我们再次执行:
ar[-1] += a
#=> ["a","b"]]
enum
然后将第三个元素传递到块。
a,"b"]]]
a #=> ["a","b"]]
因为:
a.size + ar[-1].size > 6
#=> 3 + 5 > 6 => false
这次我们执行
ar << a
#=> [["a","c"]]
其余步骤相似。