我正在尋找有關我正在構建的與足球相關的應用程式中的資料的幫助。
以此作為我正在處理的物件的樣本:
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 名球員組成的最強大的外場球隊。
- 其余4名球員將坐在替補席上。
這里的轉折點是 11 名外場球員的每個位置都需要最少和最多人數的球員。
- 守門員:1。
- 后衛:最少 3 人,最多 5 人。
- 中場:最少 2 人,最多 5 人。
- 前鋒:MIN 1,MAX 3。
對于熟悉Fantasy Premier League的人來說,規則的作業方式相同:
您的球隊可以使用任何陣型,前提是始終選擇 1 名守門員、至少 3 名后衛和至少 1 名前鋒。
我已經嘗試將陣列連接到一個大陣列并按玩家得分值對它們進行排序,但我無法弄清楚如何在遵守位置規則的同時從該點計算最強的前 11 名玩家。
任何幫助將不勝感激。
uj5u.com熱心網友回復:
我發現模塊化方法更直觀、更有彈性。
此解決方案將問題分解為首先將您的資料轉換為更有用的格式,然后找到 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}
我們從兩個可能在其他專案中使用的通用實用程式函式開始
maximumBy接受一個函式,將一個值轉換為一個可比較的值——在這個問題中,我們使用它來提取分數——并回傳一個接受一組值的函式,在每個值上運行該函式并選擇得分最高的那個。(這個版本比它可能的效率低。我現在寧愿專注于簡單性。choose查找n值陣列的所有元素子集。例如,choose (2, ['a', 'b', 'c', 'd'])回傳[['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}并回傳一個函式,該函式從小隊中獲取一個陣容并報告該陣容是否遵守所有規則。
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}}
],
}
但我只會在你不尋常的資料格式被強加給你的情況下才會這樣做。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/431785.html
標籤:javascript 数组 算法 排序 数学
