그룹

2017-12-15 22 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

주어진 예제와 매우 유사하지만 다른 속성 이름을 사용합니다. 내가 질문을 업데이트하길 원하니? 하나의 속성 유형이 많은 값을 가질 수 있다는 것도 중요합니다. 따라서 'a'는 다양한 가치를 가질 수 있습니다. @KoushikChatterjee – lukejkw

답변

3

이 Ramda의 xprod 기능은 두 목록에서 작동하는 것을 제외하고 Ramda에서 상대적으로 간단하다. 목록에서 작동하는 경우 몇 단계 만 수행하면됩니다. 그러나 쓰기 쉬운 충분 우리 자신의 : 당신은 Ramda REPL에 대한 조치에서 볼 수

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

.

+0

믿어지지 않는 대답. 이것을하기위한 단순하고 우아한 방법이 있다는 것을 알았습니다. – lukejkw