如何生成符合位置与预算要求的15人足球球员组合?
Fantasy Premier League 15人合规组合生成方案
问题1:价格与球员关联错误的解决
你之前把球员的各个字段拆成独立数组(id、first_name等),导致后续无法将价格和对应球员正确绑定。正确做法是保留每个球员的完整数据对象,不要拆分字段:
- 直接从API返回的
elements中提取每个球员的所需字段,计算好转换后的价格,将每个球员封装为一个哈希,让所有属性绑定在一起。 - 避免单独处理
price数组,而是在球员对象里直接存储转换后的价格值。
问题2:多位置组合合并的解决
Ruby的Array#product方法支持任意数量的数组参数,完全可以用来合并四个位置的组合数组。通过forward_combo.product(midfielder_combo, defender_combo, goalkeeper_combo)就能生成所有位置组合的笛卡尔积,之后再筛选总价格符合预算的组合。
修正后的完整代码
def index require 'net/http' require 'json' url = 'https://fantasy.premierleague.com/api/bootstrap-static/' uri = URI(url) response = Net::HTTP.get(uri) data = JSON.parse(response) elements = data["elements"] # 预算上限 budget = 100.0 # 1. 处理球员数据:封装为包含所需字段的哈希,直接计算转换后的价格 players = elements.map do |elem| { id: elem["id"], first_name: elem["first_name"], second_name: elem["second_name"], position: elem["element_type"], price: elem["now_cost"] / 10.to_f, total_points: elem["total_points"] } end # 2. 按位置分组 goalkeepers = players.select { |p| p[:position] == 1 } defenders = players.select { |p| p[:position] == 2 } midfielders = players.select { |p| p[:position] == 3 } forwards = players.select { |p| p[:position] == 4 } # 3. 生成各位置符合人数要求的组合 gk_combos = goalkeepers.combination(2).to_a def_combos = defenders.combination(5).to_a mid_combos = midfielders.combination(5).to_a fw_combos = forwards.combination(3).to_a # 4. 合并所有位置组合,并筛选符合预算的组合 valid_teams = fw_combos.product(mid_combos, def_combos, gk_combos).select do |fw_group, mid_group, def_group, gk_group| # 计算当前组合的总价格 total_price = fw_group.sum { |p| p[:price] } + mid_group.sum { |p| p[:price] } + def_group.sum { |p| p[:price] } + gk_group.sum { |p| p[:price] } total_price <= budget end # 可选:输出结果示例,比如第一个合规组合的球员信息和总价格 if valid_teams.any? sample_team = valid_teams.first total_price = sample_team.flatten.sum { |p| p[:price] } puts "示例合规组合(总价格:#{total_price.round(1)}):" sample_team.each_with_index do |group, idx| position_names = ["门将", "后卫", "中场", "前锋"] puts "#{position_names[idx]}:" group.each { |p| puts " #{p[:first_name]} #{p[:second_name]} - #{p[:price]} 分 - #{p[:total_points]} 点" } end else puts "没有找到符合预算的15人组合" end valid_teams end
关键代码说明
- 球员数据封装:通过
map将每个API返回的球员对象转换为精简哈希,包含所有需要的字段,价格直接转换为小数存储,彻底避免关联错误。 - 组合合并:使用
product方法一次性合并四个位置的组合数组,得到所有可能的15人组合。 - 预算筛选:对每个组合计算总价格,只保留总价格≤100的组合。
- 性能提示:由于组合数量可能非常庞大(比如前锋组合可能有成千上万种),实际运行时可以提前过滤掉价格过高的球员,或者使用更高效的算法减少计算量。
内容的提问来源于stack exchange,提问作者ldthompson
相关产品推荐
相关产品推荐

