在Crystal中,有没有办法使用group_by with_index?

时间:2018-07-23 08:47:46

标签: crystal-lang

所以我有这个(排序好的)数组。

有时我需要数组中的所有元素。但是有时候我需要所有偶数索引的成员在一起,而所有奇数索引的成员在一起。然后再说一次,有时我需要将它分为三组,一组索引为0、3、6等,然后下一组为1,4,7,最后一组为2,5,8。

这可以通过group_by并采用索引的模数来完成。亲自看看:

https://play.crystal-lang.org/#/r/4kzj

arr = ['a', 'b', 'c', 'd', 'e']
puts arr.group_by { |x| arr.index(x).not_nil! % 1 } # {0 => ['a', 'b', 'c', 'd', 'e']}
puts arr.group_by { |x| arr.index(x).not_nil! % 2 } # {0 => ['a', 'c', 'e'], 1 => ['b', 'd']}
puts arr.group_by { |x| arr.index(x).not_nil! % 3 } # {0 => ['a', 'd'], 1 => ['b', 'e'], 2 => ['c']}

但是其中的not_nil!感觉像是代码气味/警告,这是一种更好的方法。

我可以获取元素的索引而不需要查找它并处理Nil类型吗?

2 个答案:

答案 0 :(得分:5)

您也可以这样做:

class Application
  pg_search_scope :search, against: %i[email full_name id_no company_reg_no id vehicle_reg_no], using: {
    tsearch: {
      any_word: true
    },
    trigram: {
      only: %i[vehicle_reg_no full_name]
    }
  }
end

答案 1 :(得分:4)

除了nilable返回类型外,为每个元素调用Array#index也是非常低效的。这意味着运行时间为O(N²)。

#group_by用于按值分组,但是您不需要用于分组的值,因为您只想按索引分组。这比包裹#group_by#index

容易得多

一种更有效的解决方案是遍历索引并根据索引对值进行分组:

groups = [[] of Char, [] of Char]
arr.each_index do |i|
  groups[i % 2] << arr[i]
end

对此没有特殊的方法,但是实现自己非常简单。

如果不需要所有组,而只需要其中一个,则还可以使用Int32#step来迭代其他所有索引:

group = [] of Char
2.step(to: arr.size - 1, by: 3) do |i|
  group << arr[i]
end