Javascript 找到总长度为10的数组的随机组合,并可拆分为两组,每组5个
假设我有一个带有数组的数组,例如:Javascript 找到总长度为10的数组的随机组合,并可拆分为两组,每组5个,javascript,combinations,Javascript,Combinations,假设我有一个带有数组的数组,例如: const array = [ ['a', 'b', 'c'], ['d', 'e'], ['f', 'g', 'h', 'i', 'j'], ['k'], ['l'], ['m'], ['n', 'o', 'p'], ['q', 'r', 's'], ['t', 'u', 'v'], ['x'] ]; 我想随机选择符合以下规则的任意组合: 所有选定组合的总长度必须始终为10。
const array = [
['a', 'b', 'c'],
['d', 'e'],
['f', 'g', 'h', 'i', 'j'],
['k'],
['l'],
['m'],
['n', 'o', 'p'],
['q', 'r', 's'],
['t', 'u', 'v'],
['x']
];
我想随机选择符合以下规则的任意组合:
- 所有选定组合的总长度必须始终为10。可能的结果是
数组的前3项
- 所选组合必须能够分为两组,每组5个。同样,前3个项目将遵守该条件:
+['a',b',c']
的['d',e']
长度等于
,同时5
的长度等于['f',g',h',i',j']
。这是两组5
。另一方面,5
将无法满足此条件,即使它们尊重第一个元素(总长度=10)李>数组的最后4个元素
几个小时后,我想出了一个解决办法。通过了我所有的测试
//const { shuffle, flatten } = require('lodash');
const pool = [
['a', 'b', 'c'],
['d', 'e'],
['f', 'g', 'h', 'i', 'j'],
['k'],
['l'],
['m'],
['n', 'o', 'p'],
['q', 'r', 's'],
['t', 'u', 'v'],
['x']
];
function getMaxPickSize ( draw ) {
let x = 5;
let y = 5;
draw.forEach( pick => {
if ( x - pick.length >= 0 ) {
x -= pick.length;
} else if ( y - pick.length >= 0 ) {
y -= pick.length;
}
});
return Math.max(x,y);
}
function doDraw( pool ) {
//no need to move further if there arent even 10 players
if ( _.flatten(pool).length < 10 ) {
return false;
}
// keep register of all draws and pools, and items. if we
// figure out an attempt doesnt work, we can go back anytime
// and skip picks that dont work
let prevs = [
// array of objects that will look like this.
// {
// pool: [],
// draw: [],
// skip: []
// }
// ...
];
//let's try. First step, shuffle the pool;
pool = _.shuffle(pool);
function doIt( curr_pool, curr_draw = [], skip_items_w_length ) {
let new_pool = [...curr_pool];
let new_draw = [...curr_draw];
let pick;
if ( skip_items_w_length == undefined ) {
//in first loop it starts here
//if we happen to have luck and fill the draw in
//one go, the else statement below will never execute
pick = new_pool.shift();
} else {
let to_skip = prevs[prevs.length - 1].skip;
to_skip.push(skip_items_w_length);
pick = _.find(new_pool, item => !to_skip.includes(item.length) );
if ( pick ) {
new_pool.splice(new_pool.indexOf(pick), 1);
} else {
if ( !prevs.length ) {
return false;
}
let prev = prevs.pop();
let prev_pool = prev.pool;
let prev_draw = prev.draw;
let last_item_in_prev_draw = prev_draw.pop();
return doIt(prev_pool, prev_draw, last_item_in_prev_draw.length );
}
}
new_draw = [...curr_draw, pick];
//if draw is complete, return it
if ( _.flatten(new_draw).length === 10 ) {
return new_draw;
}
//else draw process continues
//find items in pool that can still fit into draw
const max_pick_size = getMaxPickSize(new_draw);
new_pool = new_pool.filter(item => item.length <= max_pick_size);
//if items dont contain enough players to fill remaining spots,
//repeat this exact step, ignoring items without pick's length
//as none of the remaining picks can follow. if we discover in
// later repeats that no pick allows other picks to follow
// we'll go back 1 step, using previous pool and draw, and
// ignoring all picks with the associated picks length
if ( _.flatten(new_pool).length < 10 - _.flatten(new_draw).length ) {
return doIt(curr_pool, curr_draw, pick.length);
}
prevs.push({
pool: curr_pool,
draw: curr_draw,
skip: []
});
return doIt(new_pool, new_draw);
}
return doIt(pool);
}
const draw = doDraw( pool );
//const{shuffle,flant}=require('lodash');
常量池=[
[a',b',c'],
['d','e'],
[f',g',h',i',j'],
[k'],
['l'],
['m'],
[n',o',p'],
[q',r',s'],
[t',u',v'],
['x']
];
函数getMaxPickSize(绘制){
设x=5;
设y=5;
draw.forEach(pick=>{
如果(x-pick.length>=0){
x-=拾取长度;
}如果(y-pick.length>=0),则为else{
y-=拾取长度;
}
});
返回Math.max(x,y);
}
函数doDraw(池){
//如果连10名球员都没有,就不需要再往前走了
如果(u.展平(池)。长度<10){
返回false;
}
//保留所有提款、池和项目的登记。如果我们
//如果你想办法不奏效,我们随时都可以回去
//跳过那些不起作用的选择
设prevs=[
//看起来像这样的对象数组。
// {
//池:[],
//提款:[],
//跳过:[]
// }
// ...
];
//让我们试试。第一步,洗牌池;
pool=\洗牌(pool);
函数doIt(当前池,当前绘图=[],跳过项目长度){
让new_pool=[…curr_pool];
让新绘图=[…当前绘图];
让我们挑选;
如果(跳过项目长度==未定义){
//在第一个循环中,它从这里开始
//如果我们运气好的话,就可以抽签了
//一次过,下面的else语句将永远不会执行
pick=new_pool.shift();
}否则{
let to_skip=prevs[prevs.length-1]。跳过;
要跳过。推送(跳过项目长度);
pick=u.find(新的_池,项=>!to_skip.includes(项.长度));
如果(选择){
新池拼接(新池索引(pick),1);
}否则{
如果(!上一个长度){
返回false;
}
设prev=prevs.pop();
让prev_pool=prev.pool;
让prev_draw=prev.draw;
让_prev_draw中的最后一个_项_=prev_draw.pop();
返回doIt(上一个池、上一个绘图、上一个绘图中的最后一个项目长度);
}
}
新绘图=[…当前绘图,拾取];
//如果抽签完成,请将其返回
如果(u.flant(新绘制).length==10){
返回新的_-draw;
}
//否则将继续绘制过程
//在池中查找仍可放入绘图的项目
常量最大拾取大小=getMaxPickSize(新绘制);
new_pool=new_pool.filter(item=>item.length洗牌数组,然后取出唯一的组,直到达到五个:
const数组=[
[a',b',c'],
['d','e'],
[f',g',h',i',j'],
[k'],
['l'],
['m'],
[n',o',p'],
[q',r',s'],
[t',u',v'],
['x']
];
函数洗牌(arr){/*这里的洗牌算法*/}
洗牌(阵法);
//提取具有精确“count”元素的数组,排除“exclude”中的所有元素,并从数组中的“start”开始
//如果未找到组合,则返回undefined
函数抽头(数组、计数、开始=0、排除=[]){
//基本情况:未精确达到计数,请在此处中止
如果(计数<0)返回;
//基本情况:发现组合,上升
if(count==0)返回[];
//检查数组以找到匹配的组合
for(设i=start;i console.log(“游戏可以开始”);
我想出的解决方案可能不是您想要的。无论如何,我认为它可能会帮助您。它会找到所有可能的组合,如果您只需要一个,您可以随机选择。我还使用