我有一个创建足球装备的脚本。
每个俱乐部只能与其他俱乐部进行一场比赛,而且可以在家里或远方。
这是我的实际代码,不适用于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个匹配项。那是为什么?
答案 0 :(得分:1)
执行此操作时:
clubs_to_play = all_clubs = Club.all
你基本上做的是:
all_clubs = Club.all
clubs_to_play = all_clubs
它们是相同的对象(如果你查看它们的object_id
,你会看到它们。)
在调用kicker方法之前,DataMapper不会实现记录集。这基本上意味着在您开始迭代之前不会执行SQL。当然,由于这些变量都指向同一个对象,当您开始迭代all_clubs
时,您从中 all_clubs
和{{1}中的数据库中提取所有记录因为它们是完全相同的对象。
相反,当你这样做时:
clubs_to_play
此处all_clubs = Club.all
clubs_to_play = Club.all
和all_clubs
引用不同的对象。也就是说,它们具有不同的clubs_to_play
,并且当您迭代object_ids
时,其所有记录都已实现,但all_clubs
保持不受影响,直到您迭代它(并从其他集合中删除值)
由于您的算法假设clubs_to_play
和all_clubs
可以彼此独立地修改,因此当它们是同一个对象时,您会得到不希望的行为。
尝试这样的(稍微更具功能性)方法:
clubs_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
返回集合中所有可能的(唯一)值组合。