【问题标题】:Datamapper assignment behaviour数据映射器分配行为
【发布时间】:2011-11-16 06:41:14
【问题描述】:

我有一个创建足球赛程的脚本。

每个俱乐部只能与其他俱乐部打一场比赛,可以是主场比赛,也可以是客场比赛。

这是我的实际代码,它不适用于 20 个俱乐部(它创建了 145 场比赛而不是 190 场比赛,并且俱乐部的​​比赛数量不同)

  clubs_to_play = all_clubs = Club.all #problematic line

  all_clubs.each do |club|
    home = true
    clubs_to_play.delete(club)
    clubs_to_play.each do |club_to_play|
      f = Fixture.new
      if (home)
        f.home = club
        f.away = club_to_play
        home = false
      else
        f.home = club_to_play
        f.away = club
        home = true
      end
      f.save
    end
  end
end

但如果我将第一行更改为:

clubs_to_play = Club.all
all_clubs = Club.all

脚本运行并生成 190 个匹配项。这是为什么呢?

【问题讨论】:

  • 在我的答案末尾查看我的编辑以获得更清洁的解决方案。

标签: ruby datamapper


【解决方案1】:

当你这样做时:

clubs_to_play = all_clubs = Club.all

你基本上在做的是这样的:

all_clubs = Club.all
clubs_to_play = all_clubs

它们是相同的对象(如果您查看他们的object_ids 就会看到)。

DataMapper 在调用 kicker 方法之前不会具体化记录集。这基本上意味着在您开始迭代之前不会执行任何 SQL。当然,由于这些变量都指向同一个对象,所以当您开始迭代 all_clubs 时,您会在 both all_clubsclubs_to_play 中从数据库中提取所有记录,因为它们是完全相同的对象

相反,当你这样做时:

all_clubs = Club.all
clubs_to_play = Club.all

这里all_clubsclubs_to_play 引用了不同的对象。也就是说,它们有不同的object_ids,当你迭代all_clubs时,它的所有记录都会被物化,但clubs_to_play在你迭代它之前不受影响(并从另一个集合中删除值)。

由于您的算法假设 all_clubsclubs_to_play 可以相互独立修改,因此当它们是同一个对象时,您会得到不希望的行为。

尝试这样的(功能稍强)方法:

Club.all.combination(2).each_with_index do |(club1, club2), idx|
  Fixture.create(
    :home => idx.even? ? club1 : club2,
    :away => idx.even? ? club2 : club1
  )
end

技术上有更多功能性的方法来保持主客场之间的交替,但它们更加复杂。 Enumerable#combination 返回集合中所有可能的(唯一)值组合。

【讨论】:

  • 这是一个很好的答案!非常感谢。不知道组合方法。我正在用 Ruby 开始一个项目,我学到了很多东西!谢谢!
猜你喜欢
  • 1970-01-01
  • 2023-03-22
  • 1970-01-01
  • 2011-10-05
  • 1970-01-01
  • 1970-01-01
  • 2014-06-11
  • 2011-11-29
  • 2019-01-02
相关资源
最近更新 更多