如何在 Ruby 中计算数组中的元素

How to count the elements in an Array in Ruby

提问人:Rubin 提问时间:2/28/2023 最后编辑:Cary SwovelandRubin 更新时间:3/1/2023 访问量:96

问:

result=  [
  {
    "range_id": 18,
    "id": 1,
    "start": 1863,
    "end": 1875,
  },
  {
    "range_id": 12,
    "id": 2,
    "start": 1820,
    "end": 1844,
  },
  {
    "range_id": 19,
    "id": 3,
    "start": 1875,
    "end": 1887,
  },
  {
    "range_id": 12,
    "id": 4,
    "start": 1844,
    "end": 1856,
  },
  {
    "range_id": 18,
    "id": 5,
    "start": 1887,
    "end": 1899,
  },
  {
    "range_id": 12,
    "id": 6,
    "start": 1856,
    "end": 1868,
  }
]

我喜欢做的是检查结果中的“range_id”值,并计算相同的range_id,如果 range_id.count <= 3,我会执行某些任务,否则跳过,但不确定如何实现。 我们可以在 ruby 中做这样的事情吗?

next unless result.range_id.count <=3
{
do something
}
数组 Ruby 解析

评论

0赞 spickermann 2/28/2023
例如,特定的喜欢?还是每个都应该至少出现 3 次?或者至少一个,不管是哪个?range_id18range_idresultrange_id
0赞 Cary Swoveland 2/28/2023
当你举例时,你应该总是显示想要的结果。结果应该是一个有效且完整的 Ruby 对象(没有“etc.”或“...”)。如果你觉得完整的期望结果太长而无法在你的答案中显示出来,这通常意味着你的例子不必要地大。有时提问者没有表现出想要的结果,因为他们认为从他们的话中应该很明显,但他们可能是错的。无论如何,举例不要超过表达你的观点所需的例子。

答:

1赞 spickermann 3/1/2023 #1

你可以用这单行来计算每个的出现次数:range_id

result.map { |hash| hash[:range_id] }.tally
#=> { 18 => 2, 12 => 3, 19 => 1 }

然后,您可以迭代该哈希,并根据其计数处理每个哈希:range_id

range_id_counters = result.map { |hash| hash[:range_id] }.tally
range_id_counters.each do |range_id, count|
  puts("#{range_id} occurs only #{count} times") if count <= 3
end
# 18 occurs only 2 times
# 12 occurs only 3 times                                                                                                                         
# 19 occurs only 1 times  
0赞 spam-elgoog 3/1/2023 #2

这里还有几个选项

  1. 您可以使用嵌套选择来获取具有 3 个或更少记录的记录
selection_of_items = result.select do |a|
    result.select { |b| b[:'range_id'] == a[:'range_id']}.size <= 3
end

selection_of_items.each do |c|
  # do something
end
  1. 您可以避免上面的 O(n^2),而不是使用数组来存储项目,您可以尝试使用哈希来代替使用range_id作为键,并使用“Set”来存储具有相同range_id的项目 例如{“18”=>{{“range_id”=>18, “id”=>1, “start”=>1863, “end”=>1875}, ...}, ...}
# using your result array from above
hash_result = {}
result.each do |obj|
  hash_result.store(
    obj[:'range_id'], hash_result.fetch(obj[:'range_id'], Set.new).add(obj)
  )
end
# then use the new structure
# {
#   18=>{{:range_id=>18, :id=>1, :start=>1863, :end=>1875}, {:range_id=>18, :id=>5, :start=>1887, :end=>1899}},
#   12=>{{:range_id=>12, :id=>2, :start=>1820, :end=>1844},{:range_id=>12, :id=>4, :start=>1844, :end=>1856},
#     {:range_id=>12, :id=>6, :start=>1856, :end=>1868}},
#   19=>{{:range_id=>19, :id=>3, :start=>1875, :end=>1887}}
# }
hash_result.each do |k,v|
  next if v.count > 3
  v.each do |d|
     #do something
  end 
end