【问题标题】:typescript : get all combinations of fixed length without repetitiontypescript : 获取所有固定长度的组合而不重复
【发布时间】:2020-05-03 21:51:08
【问题描述】:

我有以下输入:

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 个元素,这不是我想要的

剩下的问题:我不想计算名称相同的组合,我只想要 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
]
  1. 我仍然有重复名称的组合,请参阅第一个元素
  2. 我看到一些缺少的组合,例如,以下不显示:

     { name: 'john', travelMode: 'bus' },
     { name: 'kevin', travelMode: 'car' }
    

在此先感谢您的帮助,我花了几个小时试图理解并得到我想要的东西。

【问题讨论】:

    标签: javascript typescript algorithm ecmascript-6 combinations


    【解决方案1】:

    我认为混淆来自于在递归步骤中改变数组。这使得代码难以理解和调试。

    我会使用生成器函数遍历数组,获取当前索引处的元素,并从所有以下元素中获取具有 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;
    

    【讨论】:

    • 谢谢你的回答,有空我会看的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-31
    • 2023-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多