我怎样才能归还最高价值的" element - per" name" - 在数组中?

时间:2016-06-30 14:27:00

标签: ruby-on-rails arrays ruby

我已经阅读了很多关于使用max和max_by在数组中查找价值最高的对象的帖子,但我的情况更深层次,我找不到任何关于如何做的参考

我有一个实验性的Rails应用程序,我试图转换旧的.NET / SQL应用程序。 (简化)模型看起来像Overlay -> Calibration <- Parameter。在单个数据集中,我将拥有20K Calibrations,但其中大约3,000-4,000个是参数名称的版本副本,我只需要每个名称的最高版本参数。更复杂的问题是该版本存在于Overlay上。 (我知道这看起来很疯狂,但这模仿了我们的现实。)

在纯SQL中,我们将以下内容添加到查询中以创建虚拟表:

n = ROW_NUMBER() OVER (PARTITION BY Parameters.Designation ORDER BY Overlays.Version DESC)

然后选择n = 1

的条目

我可以像这样订购数组:

ordered_calibrations = mainline_calibrations.sort do |e, f|
  [f.parameter.Designation, f.overlay.Version] <=> [e.parameter.Designation, e.overlay.Version] || 1
end

我得到了这样的结果:

C_SCR_trc_NH3SensCln_SCRT1_Thd  160
C_SCR_trc_NH3SensCln_SCRT1_Thd  87
C_SCR_trc_NH3Sen_DewPtHiThd_Tbl 310
C_SCR_trc_NH3Sen_DewPtHiThd_Tbl 160
C_SCR_trc_NH3Sen_DewPtHiThd_Tbl 87

所以我想知道是否有办法使用Ruby的Enumerable内置方法循环遍历排序的数组,并且只返回每个名称的最高版本元素。如果我可以将一个整数提供给此方法的块,并且只返回最高版本的元素UP to the version version(&#34; 160&#34;将仅返回第二个和第四个条目, )。

替代方案是我可以以某种方式在ActiveRecord中实现ROW_NUMBER() OVER,但这似乎更难以尝试。当然,我可以编写代码来处理这个问题,但是我很确定它会比确定正确的Enumerable函数(如果存在的话)慢几个数量级。

(另外,要明确的是,执行.find_by_sql()并创建与遗留应用程序相同的结果集 - 它甚至很快 - 但是我很简单试图拖动所有相关的物体,这是你真的可以用这种方法做的。)

1 个答案:

答案 0 :(得分:1)

我不相信在数据库中这样做不是更好的选择,但由于我不熟悉SQL Server,我会给你一个Ruby答案。

我假设当您说“参数名称”时,您正在谈论Parameters.Designation列,因为这是您示例中的那个。

您可以使用Enumerable#slice_when的一种简单方法,可在Ruby 2.2+中使用。当你想要以某种方式在不同的值之间切换数组时,slice_when是好的。例如:

[ { id: 1, name: "foo" }, { id: 2, name: "foo" }, { id: 3, name: "bar" } ]
  .slice_when {|a,b| a[:name] != b[:name] }
# => [ [ { id: 1, name: "foo" }, { id: 2, name: "foo" } ],
#      [ { id: 3, name: "bar" } ]
#    ]

您已经对收藏品进行了分类,因此要对其进行分片,您只需要执行此操作:

calibrations_by_designation = ordered_calibrations.slice_when do |a, b|
  a.parameter.Designation != b.parameter.Designation
end

现在calibrations_by_designation是一个数组数组,每个数组都从最大Overlay.Version到最少排序。然后,最后一步是获取每个数组中的第一个元素:

highest_version_calibrations = calibrations_by_designation.map(&:first)