我有以下输入内容:
interface Option{
name:string
travelMode:string
}
const options:Option[] = [
{
name:"john",
travelMode:"bus"
},
{
name:"john",
travelMode:"car"
},
{
name:"kevin",
travelMode:"bus"
},
{
name:"kevin",
travelMode:"car"
},
]
我想在此集合中获得长度2的所有可能组合,为此,我正在这样做:
const getCombinations=(options:Option[],startIndex:number,combination:Option[],combinationSize:number)=>{
if (combination.filter(e => e!==undefined).length === combinationSize)
{
console.log(combination)
}
else if (startIndex<options.length){
combination[startIndex]=undefined
getCombinations(options,startIndex+1,combination,combinationSize)
combination[startIndex]=options[startIndex]
getCombinations(options,startIndex+1,combination,combinationSize)
}
}
getCombinations(options,0,[],2)
这似乎运行良好,我得到以下输出:
[
undefined,
undefined,
{ name: 'kevin', travelMode: 'bus' },
{ name: 'kevin', travelMode: 'car' }
]
[
undefined,
{ name: 'john', travelMode: 'car' },
undefined,
{ name: 'kevin', travelMode: 'car' }
]
[
undefined,
{ name: 'john', travelMode: 'car' },
{ name: 'kevin', travelMode: 'bus' },
undefined
]
[
{ name: 'john', travelMode: 'bus' },
undefined,
undefined,
{ name: 'kevin', travelMode: 'car' }
]
[
{ name: 'john', travelMode: 'bus' },
undefined,
{ name: 'kevin', travelMode: 'bus' },
undefined
]
[
{ name: 'john', travelMode: 'bus' },
{ name: 'john', travelMode: 'car' },
undefined,
undefined
]
但是,我有一个怀疑和一个仍然存在的问题:
我的疑问:为什么所有打印的组合的长度都为4,如果我们已经定义了2个元素,我的折断条件通常应该停止递归:我不明白为什么最后一个组合打印在我的输出中包含4个元素(前2个已定义,其余2个未定义)=>即使我的程序已经有2个元素组合,我的程序仍会继续迭代,那不是我想要的
仍然存在的问题:我不想计算名称相同的组合,我只想组合两个不同的名称(john和kevin,但不想john和john或kevin和kevin) 为此,我首先想让程序保持这样,计算所有内容,最后删除带有重复名称的组合,但是我很快意识到这不是最佳解决方案,尤其是当我的输入选项将包含更多数据时(其他人和其他人的选项)。 因此,我尝试了以下解决方案(如果我们已经拜访了个人,则停止该程序):
const getCombinations=(options:Option[],startIndex:number,combination:Option[],combinationSize:number)=>{
if (combination.filter(e => e!==undefined).length === combinationSize)
{
console.log(combination)
}
else if (startIndex<options.length){
combination[startIndex]=undefined
getCombinations(options,startIndex+1,combination,combinationSize)
let individualAlreadyVisited = false
if (startIndex>0)
{
for (let i =0;i<startIndex;i++)
{
if (combination[i] && combination[i].name===options[startIndex].name)
{
individualAlreadyVisited=true
break
}
}
}
if (!individualAlreadyVisited)
{
combination[startIndex]=options[startIndex]
getCombinations(options,startIndex+1,combination,combinationSize)
}
}
}
getCombinations(options,0,[],2)
但这不能按预期工作,我得到以下输出:
[
undefined,
undefined,
{ name: 'kevin', travelMode: 'bus' },
{ name: 'kevin', travelMode: 'car' }
]
[
undefined,
{ name: 'john', travelMode: 'car' },
undefined,
{ name: 'kevin', travelMode: 'car' }
]
[
undefined,
{ name: 'john', travelMode: 'car' },
{ name: 'kevin', travelMode: 'bus' },
undefined
]
[
{ name: 'john', travelMode: 'bus' },
undefined,
{ name: 'kevin', travelMode: 'bus' },
undefined
]
我看到一些缺少的组合,例如,未显示以下内容:
{ name: 'john', travelMode: 'bus' },
{ name: 'kevin', travelMode: 'car' }
在此先感谢您的帮助,我已经花了几个小时试图理解并得到我想要的东西。
答案 0 :(得分:0)
我认为混淆来自递归步骤中的数组变异。这使得代码难以理解和调试。
我将使用生成器函数遍历数组,获取当前索引处的元素,并从以下所有具有n-1个元素的元素中获取组合:
function* combine<T>(array: T[], n: number, start = 0, prev: T[] = []) {
if(n <= 0) {
yield prev;
return;
}
for(let i = start; i <= array.length - n; i++) {
yield* combine(array, n - 1, i + 1, [...prev, array[i]]);
}
}
const result = [...combine([1, 2, 3, 4], 2)];
要满足您的额外要求,您可以跳过已经包含的元素,例如:
if(prev.some(el => compare(el, array[i]))) continue;