Unique combinations of numbers in a set (AREV Specific)
At 06 AUG 2011 06:44:07AM William Titus wrote:
From a sorted list of numbers such as "10,20,30,40,50" I need to build an ordered list of all unique combinations without repeating elements.
In this case, the combinations would be:
10, 20, 30, 40, 50, 10*20, 10*30, 10*40, 10*50, 20*30, 20*40, 20*50, 30*40, 30*50, 40*50, 10*20*30, 10*20*40, 10*20*50, 10*30*40, 10*30*50, 10*40*50, 10*20*30*40, 10*20*30*50, 10*30*40*50, 10*20*30*40*50
The number of numbers is not fixed.
Can one of you math wizards set me on the right programmatic path (recursive or otherwise) to get me where I need to go?
Thanks!
At 06 AUG 2011 11:27AM Richard Hunt wrote:
Since I am not sure if you can delimit by using value marks and field marks rather than the commas ans asterisks, I used FOR/NEXT rather than REMOVE statements…
RESULT='
DELIMITER=*'
STRING=1:DELIMITER:2:DELIMITER:3:DELIMITER:4:DELIMITER:5
STRING=1:DELIMITER:2:DELIMITER:3:DELIMITER:4:DELIMITER:5
LAST_VALUE=COUNT(STRING,DELIMITER) + (STRING NE
) FOR VALUE=1 TO LAST_VALUE RESULT := @VM:FIELD(STRING,DELIMITER,VALUE) NEXT VALUE FOR VALUE=1 TO LAST_VALUE PREFIX=FIELD(STRING,DELIMITER,1,VALUE) SUFFIX=FIELD(STRING,DELIMITER,VALUE + 1,LAST_VALUE) LAST_SUFFIX_VALUE=COUNT(SUFFIX,DELIMITER) + (SUFFIX NE
)FOR SUFFIX_VALUE=1 TO LAST_SUFFIX_VALUERESULT := @VM:PREFIX:DELIMITER:FIELD(SUFFIX,DELIMITER,SUFFIX_VALUE)NEXT SUFFIX_VALUENEXT VALUE
RESULT=RESULT2,LEN(RESULT)
At 06 AUG 2011 02:58PM William Titus wrote:
Thanks, Richard, for taking time to send me your code. It's a lot more compact than mine and took me as far as:
1²2²3²4²5²1*2²1*3²1*4²1*5²1*2*3²1*2*4²1*2*5²1*2*3*4²1*2*3*5²1*2*3*4*5
The code I've built to this point is this:
* DATUM=" RUN=1 NUMBERS=1,2,3,4,5" CONVERT "," TO @VM IN NUMBERS HOWMANY=COUNT(NUMBERS,@VM)+(NUMBERS NE "") COMBOS=HOWMANY * HOWMANY ARRAY=" FOR X=1 TO HOWMANY FOR G=1 TO HOWMANY ARRAY=NUMBERS NEXT G NEXT X * ALLCOMBOS=" FOR X=1 TO COMBOS FOR G=1 TO HOWMANY DATUM=ARRAY LOCATE DATUM IN ALLCOMBOS USING @VM SETTING POS ELSE IF DATUM NE "" THEN IF ALLCOMBOS=" THEN ALLCOMBOS=DATUM ELSE ALLCOMBOS:=@VM:DATUM END END NEXT G NEXT X * FOR X=1 TO COMBOS D=NUMBERS FOR Y=X+1 TO COMBOS E=NUMBERS IF E NE "" THEN DATUM=D:"*":E LOCATE DATUM IN ALLCOMBOS USING @VM SETTING POS ELSE IF DATUM NE "" THEN IF ALLCOMBOS=" THEN ALLCOMBOS=DATUM ELSE ALLCOMBOS:=@VM:DATUM END END END NEXT Y NEXT X FOR X=1 TO COMBOS D=NUMBERS FOR Y=X+1 TO COMBOS E=NUMBERS FOR Z=Y+1 TO COMBOS F=NUMBERS IF E NE "" AND F NE "" THEN DATUM=D:"*":E:"*":F LOCATE DATUM IN ALLCOMBOS USING @VM SETTING POS ELSE IF DATUM NE "" THEN IF ALLCOMBOS=" THEN ALLCOMBOS=DATUM ELSE ALLCOMBOS:=@VM:DATUM END END END NEXT Z NEXT Y NEXT X *
And it gets me to:
1²2²3²4²5²1*2²1*3²1*4²1*5²2*3²2*4²2*5²3*4²3*5²4*5²1*2*3²1*2*4²1*2*5²1*3*4²1*3*5²1*4
*5²2*3*4²2*3*5²2*4*5²3*4*5
I realized that this is a kludge and only gets me to 3-digit groups, though it gets exactly what I want to that point.
I think I need a simple recursive way to minimize the code and maximize efficiency. I'm just not proficient enough as a coder at this point to know the way to get there except by adding more FOR-NEXT loops while also accounting for the maximum number of numbers the user will want to put into as many groups as possible.
Thanks again for your help.
At 08 AUG 2011 10:13AM Michael Slack wrote:
Just off the top of my head, I think you might find a FOR loop and a LOCATE BY to be simpler. I'll sketch out what I'm thinking in pseudo code.
* Start_Array is your array or row that you want to work with.
* End_Array is your resulting array or row.
CNT_START_ARRAY=COUNT(START_ARRAY, @VM) + (START_ARRAY # '')
IF CNT_START_ARRAY=0 THEN STOP PROCESS
FOR I=1 TO CNT_START_ARRAY
LOCATE START_ARRAY IN END_ARRAY BY "AL" USING @VM SETTING POS ELSEEND_ARRAY=START_ARRAYENDNEXT I
What this does is any time it doesn't find a matching value in the END_ARRAY, it put it in, in sorted order. So, if it find a duplicate value already within the END_ARRAY, it won't add it. So, in the end you get only unique values within the END_ARRAY.
Of course if this is what you're looking for, you'll need to flesh it out to fit your particular needs.
I hope this helps.
Michael Slack
At 10 AUG 2011 02:37PM Mike Ruane wrote:
Mike-
I'd use the same code as you, except using a LOOP…REMOVE to remove the items from the array, instead of the FOR…NEXT loop.
Mike
At 11 AUG 2011 04:49PM Bill Titus wrote:
Thanks, all.
Your help is much appreciated by this old dog. Now it's off to implement what's been suggested!