2017-12-15 13 views
2

に対するすべての値uniqの組み合わせを取得し、私は、属性値のセットを持っている:グループ

例:

[ 
    { 
    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); 
}; 

例:

it('given 3 attribute types should return 12 combinations',() => { 
    const inclusionAttributes: MemberAttributeValue[] = [ 
     { 
     memberAttribute: { 
      attributeName: 'gender', 
      aliases: [], 
      contentType: ContentType.String, 
      type: AttributeType.Mandatory 
     }, 
     value: 'Male' 
     }, 
     { 
     memberAttribute: { 
      attributeName: 'gender', 
      aliases: [], 
      contentType: ContentType.String, 
      type: AttributeType.Mandatory 
     }, 
     value: 'Female' 
     }, 
     { 
     memberAttribute: { 
      attributeName: 'age band', 
      aliases: [], 
      contentType: ContentType.String, 
      type: AttributeType.Mandatory 
     }, 
     value: '0-50' 
     }, 
     { 
     memberAttribute: { 
      attributeName: 'age band', 
      aliases: [], 
      contentType: ContentType.String, 
      type: AttributeType.Mandatory 
     }, 
     value: '51+' 
     }, 
     { 
     memberAttribute: { 
      attributeName: 'likes', 
      aliases: [], 
      contentType: ContentType.String, 
      type: AttributeType.Mandatory 
     }, 
     value: 'cats' 
     }, 
     { 
     memberAttribute: { 
      attributeName: 'likes', 
      aliases: [], 
      contentType: ContentType.String, 
      type: AttributeType.Mandatory 
     }, 
     value: 'dogs' 
     }, 
     { 
     memberAttribute: { 
      attributeName: 'likes', 
      aliases: [], 
      contentType: ContentType.String, 
      type: AttributeType.Mandatory 
     }, 
     value: 'goats' 
     } 
    ]; 

    const combinations = getAttributeCombinations(inclusionAttributes); 

    expect(combinations.length).toBe(12); 

    for (const combination of combinations) { 
     expect(combination.length).toBe(3); 
    } 
    }); 
+0

現在のソリューションは機能しますが、2つの属性グループに対してのみ機能します。グループbにn個の入力属性をサポートできる必要があります。だからメンバー属性cとdのそれぞれにx個の一意の値があるかもしれません。 a、b、c、dでグループ化することができます。 – lukejkw

+0

@lukejkw 3つまたは4つの属性グループに対してオブジェクト(入力オブジェクト)の例を挙げることはできますか? –

+0

これは、与えられた例と非常によく似ていますが、異なる属性名で表示されます。質問を更新してもらいたいですか?また、1つの属性タイプが多くの値を持つ可能性があることに注意することも重要です。だから、 'a'にはさまざまな価値があります。 @KoushikChatterjee – lukejkw

答えて

3

このRAMDAのxprod機能は2つのだけのリスト上で動作することを除いてRAMDAで比較的簡単になります。リストのリストで作業していれば、ほんの数ステップでこれを行うことができます。しかし、それは私たち自身を書くことは簡単です:

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,... 

あなたはRamda REPLにこの動作を確認することができます。

+0

信じられないほどの答え。これを行うためのシンプルでエレガントな方法があることを知っていました。 – lukejkw