簡體   English   中英

按子數組和大小 Ruby 拆分子數組的數組

[英]Split array of subarrays by subarrays sum size Ruby

我有一個子數組數組:

arr = [["a", "b", "c"], ["a", "b"], ["a", "b", "c"], ["a", "c"],
       ["c", "v"], ["c", "f"], ["e", "a"], ["a", "b", "v"],
       ["a", "n", "c"], ["a", "b", "m"], ["a", "c"], ["a", "c", "g"]]

我想將每個子數組的元素放入另一個數組,但子數組大小的總和必須小於或等於 6。所以我想得到這樣的東西

[["a", "b", "c", "a", "b"], ["a", "b", "c", "a", "c"],
 ["c", "v", "c", "f", "e", "a"], ["a", "b", "v", "a", "n", "c"],
 ["a", "b", "m", "a", "c"], ["a", "c", "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 方法並繼續將子 arrays 推送到新數組。 考慮以下:

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一樣遍歷可枚舉的每個元素,將任何可枚舉的 object “減少”為單個值

考慮一個例子:

# 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

這是一篇很好的文章,供進一步參考

因此,如果您以您的問題為例:

# 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"], ["a", "b", "c"], ["a", "c"],
       ["c", "v"], ["c", "f"], ["e", "a"], ["a", "b", "v"],
       ["a", "n", "c"], ["a", "b", "m"], ["a", "c"], ["a", "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", "b", "c", "a", "b"], ["a", "b", "c", "a", "c"],
  #    ["c", "v", "c", "f", "e", "a"], ["a", "b", "v", "a", "n", "c"],
  #    ["a", "b", "m", "a", "c"], ["a", "c", "g"]]

步驟如下。

enum = arr.each_with_object([[]])
  #=> #<Enumerator: [["a", "b", "c", "a", "b"], ["a", "b"],...
  #     ["a", "c", "g"]]:each_with_object([[]])>

第一個值由此枚舉器生成,傳遞給塊,並通過將數組分解應用於傳遞給塊的二元素數組來為塊值分配值。

a, ar = enum.next
   #=> [["a", "b", "c"], [[]]] 
a  #=> ["a", "b", "c"] 
ar #=> [[]] 

請參閱Enumerator#next 然后評估條件語句。

a.size + ar[-1].size > 6
  #=> 3 + 0 > 6 => false

所以我們執行:

ar[-1] += a
   #=> ["a", "b", "c"] 
ar #=> [["a", "b", "c"]]

下一個元素由enum生成,傳遞給塊,塊值被賦值。

a, ar = enum.next
   #=> [["a", "b"], [["a", "b", "c"]]] 
a  #=> ["a", "b"] 
ar #=> [["a", "b", "c"]]

評估條件語句。

a.size + ar[-1].size > 6
  #=> 2 + 3 > 6 => false

所以我們再次執行:

ar[-1] += a
   #=> ["a", "b", "c", "a", "b"] 
ar #=> [["a", "b", "c", "a", "b"]]

enum然后將第三個元素傳遞給塊。

a, ar = enum.next
   #=> [["a", "b", "c"], [["a", "b", "c", "a", "b"]]] 
a  #=> ["a", "b", "c"] 
ar #=> [["a", "b", "c", "a", "b"]] 

因為:

a.size + ar[-1].size > 6
  #=> 3 + 5 > 6 => false

這次我們執行

ar << a
  #=> [["a", "b", "c", "a", "b"], ["a", "b", "c"]] 

其余步驟類似。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM