为测序数据添加另一层验证

Ulq*_*fer 6 javascript algorithm

我正在创建一个匹配功能,将 2 个体重相同的玩家配对。

目前它正在基于相同的重量工作。现在,我的目标是为每场比赛添加一个序列。例如。

*如果玩家 1参加了第 1 场比赛,那么玩家 1 的下一场比赛应该是第 4 场或第 6 场比赛。玩家的每场比赛应该至少有 3 个、最多 6 个间隙,然后才能再次匹配该特定玩家。

我在下面提供了当前的输出和目标输出。

    const source = [
        {
            entryID: 1,
            entryName: "player1",
            weight: 1900,
            class:[],

        }, 
        {
            entryID: 2,
            entryName: "player1",
            weight: 1900,
            class:[],

        },
        {
            entryID: 3,
            entryName: "player2",
            weight: 1900,
            class:[],
        },
        {
            entryID: 4,
            entryName: "player3",
            weight: 1900,
            class:[],
        },
        {
            entryID: 5,
            entryName: "player4",
            weight: 1900,
            class:[],
        },
        {
            entryID: 6,
            entryName: "player5",
            weight: 1900,
            class:[],
        },
        {
            entryID: 7,
            entryName: "player6",
            weight: 1900,
            class:[],
        },
        {
            entryID: 8,
            entryName: "player7",
            weight: 1900,
            class:[],

        },
        {
            entryID: 9,
            entryName: "player8",
            weight: 1900,
            class:[],
        },
        {
            entryID: 10,
            entryName: "player9",
            weight: 1900,
           class:[],
        },
        {
            entryID: 11,
           entryName: "player10",
            weight: 1900,
            class:[],
        },
        {
            entryID: 12,
           entryName: "player11",
            weight: 1900,
              class:[],
        },
        {
            entryID: 13,
           entryName: "player12",
            weight: 1900,
            class:[],
        },
        {
            entryID: 14,
           entryName: "player1",
            weight: 1900,
            class:[],
        },

    ];

console.log(combine(source))

function combine(data = [], different = 0, maxGroupSize = 2) {
    const groups = [], related = [], sortedData = [...data].sort((a, b) => a.weight - b.weight),
        alreadyInRela = (setX, eName) => {
            let list = [...setX, eName]
            return related.some(rela => list.every(l => rela.has(l)))
        };
    
    sortedData.forEach((el, indx) => {
        let place = groups.findIndex( // find a place in a group forEach element, use indx as track
            g => g.names.size < maxGroupSize              // is the group incomplete ?
                && !g.names.has(el.entryName)             // is entryName not in the group list (names Set) ?
                && (el.weight - g.weight) <= different
                && !alreadyInRela(g.names, el.entryName) // is (entryName + group list) does not already used ?
                && el.class.every(c => !g.usedClasses.has(c)) // check class
        )

        if (place < 0) { // not found -> create new group
            let names = new Set().add(el.entryName)                      // create new group
            groups.push({ names, indxs: [indx], weight: el.weight, usedClasses: new Set(el.class) })  // group constitutive info 
            related.push(names)                                      // keep track of group list
        } else { // find a place in a group
            groups[place].names.add(el.entryName)  // related list is also updated
            el.class.forEach(c => groups[place].usedClasses.add(c)) // add classes
            groups[place].indxs.push(indx)        // add indx to retreive element in sortedData 
        }
    });

    return groups.reduce((r, g, i) => { // build result
        if (g.indxs.length > 1) {
            let key = `${i}_` + g.indxs.map(x => sortedData[x].weight).join('_')
            r[key] = []
            g.indxs.forEach(x => r[key].push(sortedData[x]))
        }
        return r
    }, {})
}
Run Code Online (Sandbox Code Playgroud)

当前结果:

{
  0_1900_1900: [{ // 1st match
  class: [],
  entryID: 1,
  entryName: "player1",
  weight: 1900
}, {
  class: [],
  entryID: 3,
  entryName: "player2",
  weight: 1900
}],
  1_1900_1900: [{ // 2nd match (As we can see here, player 1 has been matched again. There should be 3-6 matches before this player can be matched again)
  class: [],
  entryID: 2,
  entryName: "player1",
  weight: 1900
}, {
  class: [],
  entryID: 4,
  entryName: "player3",
  weight: 1900
}],
  2_1900_1900: [{ // 3rd match
  class: [],
  entryID: 5,
  entryName: "player4",
  weight: 1900
}, {
  class: [],
  entryID: 6,
  entryName: "player5",
  weight: 1900
}],
  3_1900_1900: [{ // 4th match
  class: [],
  entryID: 7,
  entryName: "player6",
  weight: 1900
}, {
  class: [],
  entryID: 8,
  entryName: "player7",
  weight: 1900
}],
  4_1900_1900: [{ // 5th match
  class: [],
  entryID: 9,
  entryName: "player8",
  weight: 1900
}, {
  class: [],
  entryID: 10,
  entryName: "player9",
  weight: 1900
}],
  5_1900_1900: [{ // 6th match
  class: [],
  entryID: 11,
  entryName: "player10",
  weight: 1900
}, {
  class: [],
  entryID: 12,
  entryName: "player11",
  weight: 1900
}],
  6_1900_1900: [{ // 7th match
  class: [],
  entryID: 13,
  entryName: "player12",
  weight: 1900
}, {
  class: [],
  entryID: 14,
  entryName: "player1",
  weight: 1900
}]
}
Run Code Online (Sandbox Code Playgroud)

目标结果:

{
  0_1900_1900: [{// 1st match
  class: [],
  entryID: 1,
  entryName: "player1",
  weight: 1900
}, {
  class: [],
  entryID: 3,
  entryName: "player2",
  weight: 1900
}],
  1_1900_1900: [{ //2nd match
  class: [],
  entryID: 4,
  entryName: "player3",
  weight: 1900
}, {
  class: [],
  entryID: 5,
  entryName: "player4",
  weight: 1900
}],
  2_1900_1900: [{ //3rd match
  class: [],
  entryID: 6,
  entryName: "player5",
  weight: 1900
}, {
  class: [],
  entryID: 7,
  entryName: "player6",
  weight: 1900
}],
  3_1900_1900: [{ //4th match (As we can see here, there are 2 matches before player 1 got matched again. This is my target output)
  class: [],
  entryID: 2,
  entryName: "player1",
  weight: 1900
}, {
  class: [],
  entryID: 8,
  entryName: "player7",
  weight: 1900
}],
  4_1900_1900: [{ //5th match
  class: [],
  entryID: 9,
  entryName: "player8",
  weight: 1900
}, {
  class: [],
  entryID: 10,
  entryName: "player9",
  weight: 1900
}],
  5_1900_1900: [{ //6th match
  class: [],
  entryID: 11,
  entryName: "player10",
  weight: 1900
}, {
  class: [],
  entryID: 12,
  entryName: "player11",
  weight: 1900
}],
  6_1900_1900: [{ //7th match
  class: [],
  entryID: 14,
  entryName: "player1",
  weight: 1900
}, {
  class: [],
  entryID: 13,
  entryName: "player12",
  weight: 1900
}]
}
Run Code Online (Sandbox Code Playgroud)

任何帮助将不胜感激。谢谢

Jor*_*rdy 5

此解决方案中将使用的所有变量:

  • currentPlayer--> 当前玩家,ashomeaway。例如:
{
  "entryID": 1,
  "entryName": "player1",
  "weight": 1900,
  "class": []
}
Run Code Online (Sandbox Code Playgroud)
  • match --> 表示特定比赛中的球员数组 ([ home, away])。例如:
[
  {
    "entryID": 1,
    "entryName": "player1",
    "weight": 1900,
    "class": []
  },
  {
    "entryID": 3,
    "entryName": "player2",
    "weight": 1900,
    "class": []
  }
]
Run Code Online (Sandbox Code Playgroud)
  • data --> 给出了作为初始数据的玩家数组 ( source)。
  • counter --> 每个 的计数器match
  • matchId --> counter_ home.weight_ away.weight。例如"0_1900_1900"
  • matches --> 每个键都是 的所有匹配项matchId。例如:
{
  "0_1900_1900": [
    {
      "entryID": 1,
      "entryName": "player1",
      "weight": 1900,
      "class": []
    },
    {
      "entryID": 3,
      "entryName": "player2",
      "weight": 1900,
      "class": []
    }
  ],
  "1_1900_1900": [
    {
      "entryID": 4,
      "entryName": "player3",
      "weight": 1900,
      "class": []
    },
    {
      "entryID": 5,
      "entryName": "player4",
      "weight": 1900,
      "class": []
    }
  ],
  ...
}
Run Code Online (Sandbox Code Playgroud)

分步解决方案:

  1. 循环遍历每个data
  2. 检查当前玩家是否为主机。
    • 如果是,则将其添加到match数组中并从 中删除该玩家data
    • 但如果不是,请检查是否home.entryName等于away.entryName
      • 如果是,则将其添加到match数组中,并从数据中删除该玩家。
      • 但如果不是,则将该玩家按顺序移动到接下来的 5 个玩家之后。
  3. 如果循环在home迭代中,则用 填充matchIdcounter_home.weight否则用matchId连接_away.weight
  4. 添加新属性 ,matches键为matchId,值为match

希望它会有所帮助。

const source = [
    {
        entryID: 1,
        entryName: "player1",
        weight: 1900,
        class:[],
    }, 
    {
        entryID: 2,
        entryName: "player1",
        weight: 1900,
        class:[],
    },
    {
        entryID: 3,
        entryName: "player2",
        weight: 1900,
        class:[],
    },
    {
        entryID: 4,
        entryName: "player3",
        weight: 1900,
        class:[],
    },
    {
        entryID: 5,
        entryName: "player4",
        weight: 1900,
        class:[],
    },
    {
        entryID: 6,
        entryName: "player5",
        weight: 1900,
        class:[],
    },
    {
        entryID: 7,
        entryName: "player6",
        weight: 1900,
        class:[],
    },
    {
        entryID: 8,
        entryName: "player7",
        weight: 1900,
        class:[],
    },
    {
        entryID: 9,
        entryName: "player8",
        weight: 1900,
        class:[],
    },
    {
        entryID: 10,
        entryName: "player9",
        weight: 1900,
        class:[],
    },
    {
        entryID: 11,
        entryName: "player10",
        weight: 1900,
        class:[],
    },
    {
        entryID: 12,
        entryName: "player11",
        weight: 1900,
        class:[],
    },
    {
        entryID: 13,
        entryName: "player12",
        weight: 1900,
        class:[],
    },
    {
        entryID: 14,
        entryName: "player1",
        weight: 1900,
        class:[],
    },
];

console.log(combine(source));

function combine(data) {
  let matches = {};
  let match = [];
  let matchId = '';
  let matchCounter = 0;
  let home, away;
  let currentPlayer;
  
  while(data.length) { // Step 1
    currentPlayer = data[0];
    if(match.length) { // Step 2
      away = currentPlayer;
      if(home.entryName !== away.entryName) {
        match.push(currentPlayer);
        data.shift();
        matchId += `_${currentPlayer.weight}`;
        matches[matchId] = match; // Step 4
        match = []; matchId = ''; matchCounter++;
      } else {
        arraymove(data, 0, 5);
      }
    } else {
      match.push(currentPlayer);
      home = currentPlayer;
      data.shift();
      matchId = `${matchCounter}_${currentPlayer.weight}`; // Step 3
    }
  }
  return matches;
}

function arraymove(arr, fromIndex, toIndex) {
  let element = arr[fromIndex];
  arr.splice(fromIndex, 1);
  arr.splice(toIndex, 0, element);
}
Run Code Online (Sandbox Code Playgroud)