Javascript 获取关于组的所有uniq值组合

Javascript 获取关于组的所有uniq值组合,javascript,typescript,combinations,permutation,ramda.js,Javascript,Typescript,Combinations,Permutation,Ramda.js,我有一组属性值: 例如: [ { memberAttribute: { attributeName: 'a' }, value: '1' }, { memberAttribute: { attributeName: 'a' }, value: '2' }, { memberAttribute: { attributeName: 'b' }, value: '1' }, { memberAttribut

我有一组属性值:

例如:

[
  {
    memberAttribute: { attributeName: 'a' },
    value: '1'  
  },
  {
    memberAttribute: { attributeName: 'a' },
    value: '2'  
  },
  {
    memberAttribute: { attributeName: 'b' },
    value: '1'  
  },
  {
    memberAttribute: { attributeName: 'b' },
    value: '2'  
  }
]
现在我想获得给定成员属性的所有唯一组合

因此,如果我想要成员属性“a”和“b”的唯一组合,结果将是:

[
   {
     memberAttribute: { attributeName: 'a' },
     value: '1'  
   },
   {
     memberAttribute: { attributeName: 'b' },
     value: '1'  
   }
],
[
   {
     memberAttribute: { attributeName: 'a' },
     value: '1'  
   },
   {
     memberAttribute: { attributeName: 'b' },
     value: '2'  
   }
],
[
   {
     memberAttribute: { attributeName: 'a' },
     value: '2'  
   },
   {
     memberAttribute: { attributeName: 'b' },
     value: '1'  
   }
],
[
   {
     memberAttribute: { attributeName: 'a' },
     value: '2'  
   },
   {
     memberAttribute: { attributeName: 'b' },
     value: '2'  
   }
]
我需要能够给出n个输入成员属性,但只能获得2个输入属性的期望结果

当前的解决方案:

export const getAttributeCombinations = (
  attributes: MemberAttributeValue[]
) => {
  // TODO - This algorithm only supports 2 attribute types
  // It should support any number of attribute types

  const combinations = new Array<Array<MemberAttributeValue>>();

  for (const attribute of attributes) {
    let unusedAttributes = allExcept(attribute, attributes);

    const permutate = () => {
      const combination = [attribute];
      const toRemove = new Array<Number>();

      for (let i = 0; i < unusedAttributes.length; i++) {
        const unusedAttribute = unusedAttributes[i];

        if (!attributeTypeAlreadyExists(unusedAttribute, combination)) {
          toRemove.push(i);
          combination.push(unusedAttribute);
        }
      }

      for (const index of toRemove) {
        unusedAttributes = remove(index, 1, unusedAttributes);
      }

      combinations.push(combination);
    };

    permutate();

    while (unusedAttributes.length > 0) {
      permutate();
    }
  }

  const sortedCombinations = map(sortByAttributeName, combinations);
  return uniqByCombination(sortedCombinations);
};

这在Ramda中相对简单,除了Ramda的
xprod
函数只能在两个列表上工作。如果它在列表上工作,我们只需几个步骤就可以完成。但是写我们自己的很容易:

const xproduct = reduce(pipe(xprod, map(unnest)), [[]])

const transform = pipe(
  groupBy(path(['memberAttribute', 'attributeName'])),
  values,
  xproduct
)

const inclusionAttributes = [
  {"memberAttribute": {"attributeName": "gender"}, "value": "Male"}, 
  {"memberAttribute": {"attributeName": "gender"}, "value": "Female"}, 
  {"memberAttribute": {"attributeName": "age band"}, "value": "0-50"}, 
  {"memberAttribute": {"attributeName": "age band"}, "value": "51+"}, 
  {"memberAttribute": {"attributeName": "likes"}, "value": "cats"}, 
  {"memberAttribute": {"attributeName": "likes"}, "value": "dogs"}, 
  {"memberAttribute": {"attributeName": "likes"}, "value": "goats"}
]

console.log(transform(inclusionAttributes))
//=> Male/0-50/cats, Male/0-50/dogs, Male/0-50/goats, Male/51+/cats,...

您可以在

上看到这一点。当前解决方案有效,但仅适用于2个属性组。我需要能够支持n组b的输入属性。因此,可能存在成员属性c和d,每个属性都有x个唯一值。您应该能够按a、b、c和d进行分组。@lukejkw您能为3或4属性组提供一个示例对象(输入对象)吗?它看起来与给出的示例非常相似,但属性名称不同。你想让我更新这个问题吗?还需要注意的是,一个属性类型可以有多个值。所以“a”可以有很多不同的值@KoushikChatterjeehm,不要改变这一点,如果需要,可以为3个属性添加另一个示例输入来更新问题possible@KoushikChatterjee我已经为3个属性添加了失败的jest测试,增加了答案。我知道有一种简单优雅的方法可以做到这一点,拉姆达。
const xproduct = reduce(pipe(xprod, map(unnest)), [[]])

const transform = pipe(
  groupBy(path(['memberAttribute', 'attributeName'])),
  values,
  xproduct
)

const inclusionAttributes = [
  {"memberAttribute": {"attributeName": "gender"}, "value": "Male"}, 
  {"memberAttribute": {"attributeName": "gender"}, "value": "Female"}, 
  {"memberAttribute": {"attributeName": "age band"}, "value": "0-50"}, 
  {"memberAttribute": {"attributeName": "age band"}, "value": "51+"}, 
  {"memberAttribute": {"attributeName": "likes"}, "value": "cats"}, 
  {"memberAttribute": {"attributeName": "likes"}, "value": "dogs"}, 
  {"memberAttribute": {"attributeName": "likes"}, "value": "goats"}
]

console.log(transform(inclusionAttributes))
//=> Male/0-50/cats, Male/0-50/dogs, Male/0-50/goats, Male/51+/cats,...