【问题标题】:Rails 4: using offset on a randomized list produces unexpected resultsRails 4:在随机列表上使用偏移量会产生意想不到的结果
【发布时间】:2017-01-09 15:19:55
【问题描述】:

...或者,我只是不明白。

TL;DR - 我得到完全随机的结果,重复等。不知道为什么。

这就是问题所在 - 我正在尝试制作一个生成锦标赛括号的 Rails 应用程序。用户可以在生成括号时选择是否要随机分配团队列表,或者稍后自行分配团队。

如果我选择后一个选项并根据 ID 生成括号,一切都很好。 如果我选择随机化列表,则列表本身很好,但是稍后在将团队分配给特定比赛时(在循环中),结果完全无组织且出乎意料(至少对我而言)。

而不是
第 1 场比赛:第 1 队对第 2 队
第 2 场比赛:第 3 队对第 4 队
等(如在正常生成的列表中)

我得到一些完全随机的东西,经常重复,比如:
第 1 场比赛:第 1 队对第 1 队
第 2 场比赛:第 1 队对第 9 队

if @seed = 'random'
  @team_list = @tournament.teams.order("RAND()")
else
  @team_list = @tournament.teams.order(:id)
end

这是我分配团队的方式。搞砸一切的东西似乎是“偏移”部分,我不明白,为什么。

@match.team_a = @team_list.offset((2*match_number)-2).limit(1).first               
@match.team_b = @team_list.offset((2*match_number)-1).limit(1).first

编辑:

根据要求提供@team_list 数据样本。那是随机的。

#<ActiveRecord::AssociationRelation 
[#<Team id: 2, team_name: "test_team_a", reputation: 0, created_at: "2016-08-25 09:29:20", updated_at: "2016-08-26 11:08:21", team_leader_id: 2>, 
#<Team id: 9, team_name: "test_team_b", reputation: 0, created_at: "2016-08-30 23:01:17", updated_at: "2016-08-30 23:01:17", team_leader_id: 2>, 
#<Team id: 3, team_name: "test_team_c", reputation: 0, created_at: "2016-08-30 22:59:16", updated_at: "2016-08-30 22:59:16", team_leader_id: 2>, 
#<Team id: 7, team_name: "test_team_d", reputation: 0, created_at: "2016-08-30 23:00:35", updated_at: "2016-08-30 23:00:35", team_leader_id: 2>, 
#<Team id: 5, team_name: "test_team_e", reputation: 0, created_at: "2016-08-30 23:00:07", updated_at: "2016-08-30 23:00:07", team_leader_id: 2>, 
#<Team id: 6, team_name: "test_team_f", reputation: 0, created_at: "2016-08-30 23:00:23", updated_at: "2016-08-30 23:00:23", team_leader_id: 2>, 
#<Team id: 4, team_name: "test_team_g", reputation: 0, created_at: "2016-08-30 22:59:41", updated_at: "2016-08-30 22:59:41", team_leader_id: 2>, 
#<Team id: 8, team_name: "test_team_h", reputation: 0, created_at: "2016-08-30 23:00:46", updated_at: "2016-08-30 23:00:46", team_leader_id: 2>]>

【问题讨论】:

  • 您能在@team_list 中添加一个数据样本吗?
  • 现在添加:)

标签: ruby-on-rails random generator offset


【解决方案1】:

只是为了更清楚地了解上述答案,当您执行 @team_list = @tournaments.teams.order("RAND()") 时,会执行此查询(大概在 SQL 中):

SELECT teams.* FROM teams ORDER BY RAND()

(我知道球队属于锦标赛,但你明白我的意思。)

然后当您执行@team_list.offset(x).limit(1) 时,会执行以下查询:

SELECT teams.* FROM teams ORDER BY RAND() LIMIT 1 OFFSET x

因为 ActiveRecord 关系,每次你做一个新的事情,你就是在做一个查询。您可以在 Rails 控制台中对此进行测试 - 它会告诉您它所做的查询。

编辑:

如果您想按原样使用代码,只需将第一个查询的结果转换为数组,不要使用偏移量/限制。所以:

@team_list = @tournaments.teams.order("RAND()").to_a
...
@match.team_a = @team_list[2 * match_number - 2]
@match.team_b = @team_list[2 * match_number - 1]

这意味着您将一次加载所有团队(我认为),而不是像 ActiveRecord 关系允许您那样懒惰地加载它们。

【讨论】:

  • 你可能是对的,我只是在问,因为我似乎仍然不明白它的工作方式。我在控制台中尝试过,每次尝试@team_list 时,我都会得到相同的结果,但是当使用偏移量时,结果是随机的。我不明白为什么在第一种情况下结果不是随机的。
  • 呃老实说,我不是 ActiveRecord 关系如何工作的专家,所以我不确定我给出的任何解释在技术上是否准确。但我的猜测是,当您将@team_list 分配给查询结果时,关系将顺序保存到变量中,但它背后仍然带有等效查询。我将更新我的答案以包含替代方案。
  • 是的,您的回答恰到好处。谢谢你
【解决方案2】:

这是因为您使用了偏移量。每次更改 match_number 时,您最终都会执行一个新查询(包括对 order_by rand() 的调用)。您需要使 @team_list 成为数据库查询的结果,然后以其他方式组织匹配项,这样您就不会重复访问数据库。这也将显着提高性能。

尝试类似的东西

@team_list.each_slice(2) do |team_a, team_b|
end

【讨论】:

  • 我想我仍然需要抵消它,因为根据我的理解,这样它只会将前两支球队分配给每场比赛。这就是为什么我首先使用偏移量。也许您知道如何以其他方式解决它?另外,也许我仍然对它的理解不正确,但是当我每次尝试@team_list 在控制台中尝试时,结果似乎是相同的(并且每次查询时都不是随机的),但是当使用偏移量时,结果是随机的。
  • each_slice docs。如果您的团队是 [1, 2, 3, 4],那么each_slice(2) 将在您的第一次迭代中为您提供 [1, 2],在您的下一次迭代中为您提供 [3, 4]。
  • @user3758208 这只是为了替换你的循环部分,你仍然需要 if 种子部分,否则它不会被随机化。您遇到的问题是,每次您使用偏移量分配一个团队时,它都会从列表中获取第 n 个团队,其顺序与之前的完全不同。
猜你喜欢
  • 1970-01-01
  • 2017-03-19
  • 2021-10-04
  • 1970-01-01
  • 1970-01-01
  • 2021-12-28
  • 2019-04-05
  • 1970-01-01
  • 2017-02-10
相关资源
最近更新 更多