希望从一个数组对象中形成 2 组数据 - Javascript

Looking to form 2 sets of data from a object of arrays - Javascript

我正在寻求有关我正在构建的足球相关应用程序中的数据的帮助。

以此作为我正在处理的对象的样本:

const squad = {
  goalkeepers: [
    { player1: { score: 10 } },
    { player2: { score: 12 } }
  ],
  defenders: [
    { player3: { score: 3 } },
    { player4: { score: 19 } },
    { player5: { score: 5 } },
    { player6: { score: 21 } },
    { player7: { score: 6 } },
  ],
  midfielders: [
    { player8: { score: 7 } },
    { player9: { score: 1 } },
    { player10: { score: 18 } },
    { player11: { score: 11 } },
    { player12: { score: 8 } },
  ],
  attackers: [
    { player13: { score: 7 } },
    { player14: { score: 2 } },
    { player15: { score: 16 } }
  ]
}

这里有15个玩家,我想把他们分成两组:

这里的不同之处在于,11 名外场球员的每个位置都需要最少和最多的球员人数。

对于熟悉 Fantasy Premier League 的任何人,规则的工作方式相同:

Your team can play in any formation providing that 1 goalkeeper, at least 3 defenders and at least 1 forward are selected at all times.

我已经尝试将数组连接到一个大数组并按玩家得分值对它们进行排序,但我无法在遵守位置规则的同时计算出从那一点开始最强的前 11 名玩家。

如有任何帮助,我们将不胜感激。

我发现模块化方法更直观、更有弹性。

此解决方案将问题分解为首先将您的数据转换为更有用的格式,然后找到 11 个玩家的所有组合,然后过滤掉不符合规则的那些,然后选择最大的那个得分:

// utility functions
const maximumBy = (fn) => (xs) => 
  xs .reduce ((a, x, i) => fn (x) > fn (a) ? x : a, xs [0] || null)

const choose = (n, xs) =>
  n < 1 || n > xs .length
    ? []
  : n == 1
    ? [...xs .map (x => [x])]
  : [
      ...choose (n - 1, xs .slice (1)) .map (ys => [xs [0], ...ys]),
      ...choose (n , xs .slice (1))
    ]


// helper functions
const simplify = (squad) => 
  Object .entries (squad) .flatMap (
    ([position, vs]) => vs .flatMap (
      (v) => Object.entries (v) .flatMap (([name, s]) => ({position, name, ...s}))
    )
  )

const validate = (rules) => (lineup) => rules .every (({position, min, max}) => {
   const count = lineup .filter (({position: p}) => p == position) .length
   return count >= min && count <= max
})

const totalScore = (lineup) =>
  lineup .reduce ((t, {score}) => t + score, 0)


// main function
const bestLineup = (squad, rules) => 
  maximumBy (totalScore) (choose (11, simplify (squad)) .filter (validate (rules)))


// sample data
const rules = [{position: 'goalkeepers', min: 1, max: 1}, {position: 'defenders', min: 3, max: 5}, {position: 'midfielders', min: 2, max: 5}, {position: 'attackers', min: 1, max: 3}]

const squad = {goalkeepers: [{player1: {score: 10}}, {player2: {score: 12}}], defenders: [{player3: {score: 3}}, {player4: {score: 19}}, {player5: {score: 5}}, {player6: {score: 21}}, {player7: {score: 6}}], midfielders: [{player8: {score: 7}}, {player9: {score: 1}}, {player10: {score: 18}}, {player11: {score: 11}}, {player12: {score: 8}}], attackers: [{player13: {score: 7}}, {player14: {score: 2}}, {player15: {score: 16}}]}


// demo
console .log (bestLineup (squad, rules))
.as-console-wrapper {max-height: 100% !important; top: 0}

我们从可能在其他项目中使用的两个 general-purpose 实用函数开始

  • maximumBy 接受一个将值转换为可比较值的函数——在这个问题中我们用它来提取分数—— return 一个接受值数组的函数,对每个值运行该函数并选择得分最高的一个。 (这个版本的效率比它应该的要低。我现在宁愿专注于简单性。

  • choose 查找值数组的 n 元素的所有子集。例如,choose (2, ['a', 'b', 'c', 'd']) returns [['a', 'b'], ['a', 'c'], ['a', 'd']. ['b', 'c'], ['b', 'd'], ['c', 'd']].

然后我们有一些辅助函数,

  • simplify 将您最初的 squad 格式变成更易于处理的格式:

    [
      {name: "player1", position: "goalkeepers", score: 10},
      {name: "player2", position: "goalkeepers", score: 12},
      {name: "player3", position: "defenders", score: 3},
      // ...
      {name: "player15", position: "attackers", score: 16}
    ]
    
  • validate接受一个规则数组,例如

    {position: 'defenders', min: 3, max: 5}
    

    和 return 是一个从小队中获取阵容并报告该阵容是否遵守所有规则的函数。

  • totalScore取一个阵容,总结所有选手的得分

最后,我们的主要功能,bestLineup 接受一个小队和一组规则,简化 小队,选择 11 名球员的所有阵容,将其过滤为仅根据规则 验证 的球员,并通过 我们的函数选择 最大值 我们计算他们的 总分.

如果您希望输出与输入格式相同,我们可以再调用一个助手来撤消我们的simplify;我们称它为 complexify:

const complexify = (xs) => 
  xs .reduce (
    (a, {name, position, score}) => (
      (a [position] = a [position] || []), (a [position] .push ({[name]: {score}})), a
    ), {})

这会将上面使用的简单格式的数组转换回如下所示:

{
    goalkeepers: [
        {player2: {score: 12}}
    ],
    defenders: [
        {player4: {score: 19}},
        {player5: {score: 5}},
        {player6: {score: 21}},
        {player7: {score: 6}}
    ],
    midfielders: [
        {player8: {score: 7}},
        {player10: {score: 18}},
        {player11: {score: 11}},
        {player12: {score: 8}}
    ]
    attackers: [
        {player13: {score: 7}},
        {player15: {score: 16}}
    ],
}

但只有当您的不寻常数据格式被强加给您时,我才会这样做。