【问题标题】:ruby / splitting array into columnsruby / 将数组拆分为列
【发布时间】:2015-12-14 01:02:27
【问题描述】:

我本可以找到正确的命名方式,但到目前为止没有出现任何问题。我会考虑将数组拆分为列。

意思是,有[0,1,2,3,4,5,6,7,9],我想要4个数组(4列):

[ [0,4,9], [1,5], [2,6], [3,7] ]

实际上,我会考虑迭代一个活动记录数组,在 4 个不同的 html 列中显示这些(它们是图像记录),同时保持它们从左到右的顺序

【问题讨论】:

  • 我认为你在结果中输了 8 个。 :)
  • 你只关心有九个元素的数组吗?如果没有,您必须告诉我们您要实施的规则?
  • @BroiSatse 是的,确实(:
  • @CarySwoveland 一点也不

标签: ruby-on-rails arrays ruby


【解决方案1】:

导轨解决方案

在 Rails 中,您可以简单地这样做:

ary = [0,1,2,3,4,5,6,7,8,9]
ary.in_groups_of(4).transpose.map(&:compact)
  #=> [[0, 4, 8], [1, 5, 9], [2, 6], [3, 7]]

解释:

in_groups_of 是添加到 Array 类的一个很酷的 rails 方法,它的行为与each_slice 非常相似,不同之处在于它保证所有数组的大小相同。这里很重要,所以我们可以稍后使用transpose。此方法返回您的行数组。

现在,transpose - 另一个值得了解的酷方法。它需要一个数组数组,并且所有内部数组的长度必须相同(因此实际上这表示一个矩形矩阵)。它的作用 - 它在目标数组中返回一个列数组。

现在我们需要摆脱 nils(除非它们不会打扰您),因此我们在每一列上运行 compact,而我们正是您想要的。

纯红宝石溶液:

我们没有in_groups_of,所以我们需要在没有它的情况下实现相同的行为:

ary.each_slice(4).map {|a| a.fill nil, a.size, 4 - a.size}.transpose.map(&:compact)

更好地解决实际问题

实际上,我会考虑迭代一个活动记录数组, 在 4 个不同的 html 列中显示这些(它们是图像记录), 同时保持从左到右的顺序

除非是表格数据,否则切勿使用表格来显示数据。图像不是表格数据,这意味着该特定图像在给定列/行的位置是完全不相关的。总有更好的方法来做到这一点。

在您的情况下,我建议使用纯 CSS 解决方案 (haml):

%ul.images
  - @images.each do |i|
    %li= image_tag i.iamge_url    # or sth

然后在你的css(scss)中:

ul.images {
  width: 100%;
  font-size: 0;    # remove whitespace between li elements
  li {
    display: inline-block;
    width: 25%;   # forcing 25% without whitespaces guarantees 4 column
  }
}

此模型的主要优点是您可以使列数取决于媒体查询,因此每行显示不同数量的图像取决于您的用户屏幕尺寸(对移动设备很重要)。

如果您更喜欢冒险并且讨厌 IE 并且不关心它的用户,那么您也可以去看看 flex-boxes。有一天它可能会成为一种标准,并且已经可以在许多页面上看到。

【讨论】:

  • 我无法让您的纯 Ruby 解决方案正常工作。对我来说,你的 each_slice 块返回 nil。
  • @6ftDan - 感谢您的关注,现已修复。
【解决方案2】:

我有一个简短的解决方案:-)

x = [0, 1, 2, 3, 4, 5, 6, 7, 9]

x.group_by.with_index {|_,index| index % 4 }.values
# => [[0, 4, 9], [1, 5], [2, 6], [3, 7]]

我已在 Ruby: Arrays by Example 上发布了一篇博文以获取视觉资源。

【讨论】:

  • 我以前不知何故错过了您的解决方案。很有创意!
【解决方案3】:

这应该可以解决问题:

input = [0,1,2,3,4,5,6,7,8,9]
max_columns = 4
input.each_with_index.with_object([]) do | (val, index), output|
    i = index % max_columns
    (output[i] ||= []).push(val)
end

【讨论】:

  • 我建议您要么在末尾添加output 行,或者最好删除output = [] 并将第4 行更改为input.each_with_index.with_object([]) do | (val, index), output|
  • 根据你的建议改了,我不知道with_object的方法,好像很有用!
【解决方案4】:

或者通过使用SLICE将大数组分割成更小的数组

input = Array(1 .. 33)

output = input.each_slice(4).to_a

output.each do |x| puts "#{x}" 
end

输出:

[1, 2, 3, 4]
[5, 6, 7, 8]
[9, 10, 11, 12]
[13, 14, 15, 16]
[17, 18, 19, 20]
[21, 22, 23, 24]
[25, 26, 27, 28]
[29, 30, 31, 32]
[33]

fyi ,不完全是数组的数组,而是要研究的东西。

【讨论】:

  • 只要它保持可迭代......它就是一个“数组数组”
  • 幕后,是的:)
【解决方案5】:

我假设如果数组的大小没有被4 均匀划分,那么第一个这么多切片数组的大小将相同,并且每个数组的元素都比每个剩余的切片数组多一个元素。 您可以通过以下几种方式做到这一点。

arr = [1,2,3,4,5,6,7,8,9]

计算具有额外元素的数组的数量

def split_it(n, arr)
  std_arr_size, nbr_bonus_arrays = arr.size.divmod(n)
  nbr_bonus_elements = nbr_bonus_arrays * (std_arr_size + 1)
  arr[0...nbr_bonus_elements].each_slice(std_arr_size+1).to_a +
    arr[nbr_bonus_elements..-1].each_slice(std_arr_size).to_a
end

split_it(1, arr)  #=> [[1, 2, 3, 4, 5, 6, 7, 8, 9]] 
split_it(2, arr)  #=> [[1, 2, 3, 4, 5], [6, 7, 8, 9]] 
split_it(3, arr)  #=> [[1, 2, 3], [4, 5, 6], [7, 8, 9]] 
split_it(4, arr)  #=> [[1, 2, 3], [4, 5], [6, 7], [8, 9]]  
split_it(5, arr)  #=> [[1, 2], [3, 4], [5, 6], [7, 8], [9]] 
split_it(6, arr)  #=> [[1, 2], [3, 4], [5, 6], [7], [8], [9]] 
split_it(7, arr)  #=> [[1, 2], [3, 4], [5], [6], [7], [8], [9]] 
split_it(8, arr)  #=> [[1, 2], [3], [4], [5], [6], [7], [8], [9]] 
split_it(9, arr)  #=> [[1], [2], [3], [4], [5], [6], [7], [8], [9]] 

使用递归

def split_it(n, arr)
  return [arr] if n==1
  m = (arr.size.to_f/n).ceil
  [arr.first(m)] + split_it(n-1, arr[m..-1])
end

split_it(1, arr)  #=> [[1, 2, 3, 4, 5, 6, 7, 8, 9]] 
split_it(2, arr)  #=> [[1, 2, 3, 4, 5], [6, 7, 8, 9]] 
split_it(3, arr)  #=> [[1, 2, 3], [4, 5, 6], [7, 8, 9]] 
split_it(4, arr)  #=> [[1, 2, 3], [4, 5], [6, 7], [8, 9]]  
split_it(5, arr)  #=> [[1, 2], [3, 4], [5, 6], [7, 8], [9]] 
split_it(6, arr)  #=> [[1, 2], [3, 4], [5, 6], [7], [8], [9]] 
split_it(7, arr)  #=> [[1, 2], [3, 4], [5], [6], [7], [8], [9]] 
split_it(8, arr)  #=> [[1, 2], [3], [4], [5], [6], [7], [8], [9]] 
split_it(9, arr)  #=> [[1], [2], [3], [4], [5], [6], [7], [8], [9]] 

【讨论】:

    【解决方案6】:

    纯 Ruby 解决方案。

    def split(n, arr)
      arr.each_with_index.reduce(Array.new(n) { [] }) do |a, (e, i)|
        a[i%n] << e
        a
      end
    end
    

    更新:正如 Cary 所建议的那样。它使用with_object()而不是reduce(),并在使用时懒惰地初始化子数组。

    def split(n, arr)
      arr.each_with_index.with_object([]) { |(e, i), a| (a[i%n] ||= []) << e }
    end
    

    【讨论】:

    • 你可以写:arr.each_with_index.with_object([]) { |(e,i),a| (a[i%n] ||= []) &lt;&lt; e }.
    • @CarySwoveland 好建议。在使用reduce() 时,它避免了附加语句a 返回累积的对象。下次还会用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-05
    • 1970-01-01
    相关资源
    最近更新 更多