Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Counting sequences without repetition in VFP 1

Status
Not open for further replies.

Eliott

Programmer
Nov 8, 2009
91
BA
Hi there,
I have fallen, as has often been said, in the problem that I can't to solve elegantly. I should make a program that generates from the Y elements a sequences of X members without repetition. I know how to get numbers of such series (for sequence 4 of 6 there is 15 possible cases...)
I made it simply by using nested few FOR...NEXT statements
Code:
*1 2 3 4
*1 2 3 5
*1 2 3 6
*1 2 4 5
*1 2 4 6
*1 3 4 5
...
*3 4 5 6

* 4 of 6
bel=6  && number of elements at all
raz=4  && how much elements in each sequence (class)
*----
FOR a= 1 TO bel
FOR b=a+1 TO bel
FOR c=b+1 TO bel
FOR d=c+1 TO bel
? a,b,c,d
NEXT d
NEXT c
NEXT b
NEXT a
but in my case there are some situation where I don't know for sure number of elements and "class", so I can't presume and use above way. Is there some way where I could input number of elements at all (6) and number of elements in each sequence (4) in order to meet my needs? I heard about recursion programming but I didn't saw some example.
Thank you.

There is no good nor evil, just decisions and consequences.
 
[ ]

Not sure what you are trying to do.

However, 'bel' and 'raz' can be dynamic variables and not static variables like you are using them. Just programatically set them to whatever inputs you want. Don't know if that will solve your problem since I don't understand what your problem is.

mmerlinn


Poor people do not hire employees. If you soak the rich, who are you going to work for?

"We've found by experience that people who are careless and sloppy writers are usually also careless and sloppy at thinking and coding. Answering questions for careless and sloppy thinkers is not rewarding." - Eric Raymond
 
Eliott,
I am not 100% sure what you are asking for (Is English not your native language? Anyhow here is some code that I whipped up that might do what you want, let me know what you think.

Code:
ACTIVATE SCREEN
CLEAR

&&-- Assuming that the elements in the result are integers but code could 
&&-- be adjusted for other data types (such as characters ) very easily

	LOCAL Sec 
	m.Sec = SECONDS()
	SET CARRY ON &&-- We want to copy the current rows information!
	
	PUBLIC Cols_to_Populate
	m.Cols_to_Populate = 8 &&-- Adjust as needed
	
	LOCAL I

&&-- Create a cursor that will hold the wanted results
&&-- Add more columns as needed
	CREATE CURSOR qResults (Col1 I, COl2 I, Col3 I, Col4 I, Col5 I, COl6 I )

&&-- Creating and populating cursor that contains the elemts that will be used to populate the qResults
&&-- In this example there will be 8 elements, adjust as needed
	CREATE CURSOR qElements ( Value I, Col_used I )
	
	FOR m.I = 1 TO m.Cols_to_Populate
		APPEND BLANK
		replace qElements.Value WITH m.I
		replace Col_Used 		WITH 0
	ENDFOR

&&-- Do the actual population of the qResults	
	
	SELECT qResults
	APPEND BLANK
	Populate_qResults_Row( 1 )

&&-- A few record needs to be deleted
	SELECT qResults
	DELETE FOR RECNO() <= fcount( [qResults] ) &&-- First few record needs to be deleted
	FOR m.I =  1 TO FCOUNT( [qResults] )
		m.Command = [Delete for qResults.Col] + ALLTRIM( STR( m.I ) ) + [ = 0 ]
		&Command				
	ENDFOR

? [Total Time: ]
?? SECONDS() - Sec
? [Records: ] 
?? RECCOUNT( [qResults] )

GO top
SET DELETED on
BROWSE normal

&& End
	
&&--------------------------------------------------------------------	
PROCEDURE Populate_qResults_Row( pCol )	

	LOCAL m.Last_qElement_Record_Found 
	m.Last_qElement_Record_Found = 0


	DO WHILE .T.

		SELECT qElements
		&&Next line is key! Finding an unused Element
		LOCATE FOR qElements.Col_Used = 0 AND RECNO() > m.Last_qElement_Record_Found 
		IF NOT FOUND()
			&&-- When we have run out of elements reset for the next loop
			replace ALL qElements.Col_Used WITH 0 FOR qElements.Col_Used = 	m.pCol
RETURN &&<<<<<<<<<<<<<<<<<<<< Escaping the Procedure 	
		ELSE
			m.Last_qElement_Record_Found = RECNO()
			replace ALL qElements.Col_Used WITH 0 FOR qElements.Col_Used = 	m.pCol
			
			GOTO m.Last_qElement_Record_Found
			replace qElements.Col_Used WITH m.pCol

			&&-- Hmmm the SET CARRY on command should make the scatter and gather
			&&-- Unneeded, but alias SET CARRY is not working like I expect
				SET CARRY on
				
				SELECT qResults
				GO bottom
				SCATTER Name m.oData
				APPEND BLANK
				GATHER NAME m.oData
				
			m.Command = [Replace qResults.Col] + ALLTRIM( STR( m.pCol ) ) + [ with qElements.Value ]
			&Command
							
			&&-- Clear out the remaining columns
				LOCAL J
				FOR m.J =  m.pCol + 1 TO FCOUNT( [qResults] )
					m.Command = [Replace qResults.Col] + ALLTRIM( STR( m.J ) ) + [ with 0 ]
					&Command				
				ENDFOR
				
										
			IF pCol < FCOUNT( [qResults] )
				Populate_qResults_Row( pCol+1 )
			Endif
		ENDIF
	ENDDO
	

ENDPROC &&-- Populate_qResults_Row


Lion Crest Software Services
Anthony L. Testi
President
 
Hi guys,
unfortunately English isn't my native language, and I try to explain my problem. This problem could be named as combination without repetitions, where I must to make sequences per 4 in a row from 6 elements, but without repetitions. Based on some knowledge from mathematics I found that "from 6 choose 4" produce 15 different combination. When a man know at start how much elements (6) and how much elements belongs into each row or sequence (4) it's easy to solve by using few nested FOR...NEXT statements, as in my first post.
But, problem is that I should to make code that will be able to count and write all combination without repetitions just based on two data: total of elements (6) and number of elements in each combination (4). I made following solution in VB but don't know how to transfer it into VFP:
Code:
Module Module1
    Dim NumOfElements As Integer
    Dim CounterOfLines As Integer
    Dim NumInSeq As Integer
    Dim Seq(100) As Integer
    Sub main()
        Console.WriteLine("Enter number of elements: (6)")
        NumOfElements = Console.ReadLine()
        Console.WriteLine("How much elements in each combination: (4) ")
        NumInSeq = Console.ReadLine()
        PrintComb(NumInSeq, 1, 0)
    End Sub

    Function PrintComb(ByVal NumInSeq As Integer, ByVal Position As Integer, ByVal z As Integer) As String
        If NumInSeq = False Then
            CounterOfLines = CounterOfLines + 1
            Console.WriteLine(" ")
            Console.WriteLine("Combination nr. : --- ", CounterOfLines, " --- ")
            Console.WriteLine(" ")
            For i As Integer = 0 To z
                Console.WriteLine(Seq(i))
            Next i

        Else : For i As Integer = Position To (NumOfElements - NumInSeq + 1)
                Seq(z) = i
                PrintComb((NumInSeq - 1), (i + 1), (z + 1))
            Next
        End If

    End Function
End Module
Thanks in advance.
@MrDataGuy: thanks man for the code, I tried it but didn't help me in this case.

There is no good nor evil, just decisions and consequences.
 
You "heard about recursion programming but I didn't saw some example."

Well, the sample you gave is a recursive function, PrintComb() does call PrintComb() in some cases and this is recursing.

I don't see what is so hard to translate that into foxpro code.

Console.Readline can be done by Inputbox().

Console.Writeline simply is ? in foxpro.

Dim...As ... is a variable declaration and either you skip that in foxpro or use LOCAL variablename.

In foxpro parameters are received ByVal by default so you don't need to specify this.

The only thing very different in foxpro from VB is, that in VB the integer 0 can also be interpreted as False and all other integers can be interpreted as True, so you'll need to change the line "IF NumInSeq = False" to "IF NumInSeq = 0"

Bye, Olaf.
 
Me again,
Hi Olaf, when I said that I "heard about recursion..." I thought about this particular example in VFP. I made this in VB but despite some changes to match VFP (1. element of subscript is always 1) by running in VFP I got just first 3 combination:
1 2 3 4
1 2 3 5
1 2 3 6
Simply program after this 3rd combination leave procedure and stop. Yes I know it shall 3rd place increase to 4 and 4th place decrease to 5... until last combination 3 4 5 6 but by this way I can't see where is a catch. Do you?

There is no good nor evil, just decisions and consequences.
 
How should I know why your VFP version of that VB code stops early, when you don't show it?

Bye, Olaf.
 
Ok Olaf, here is what I did in VFP:
Code:
*Combination without repetiton
*It shall make 15 sequences, 4 of 6, it just make first 3
CLEAR
NumOfElements=6
PUBLIC NumInSeq
NumInSeq=4
r=0
DIMENSION Seq(15)

DO PrintComb WITH NumInSeq,1,1
? 'End of program'

PROCEDURE PrintComb 
	PARAMETERS picker, position, z
	IF picker=0
		r=r+1
		? STR(r,2,0) + '.)' font 'Arial' style 'b'
		FOR i=1 TO z-1
			?? Seq(i)
		NEXT i
	ELSE
		ke=(NumOfElements-picker +1)
		FOR k=position TO ke
			Seq(z)=k
			p1=picker-1
			p2=k+1
			p3=z +1
			DO PrintComb WITH p1,p2,p3
		NEXT k
	ENDIF
ENDPROC
I tried a lot of changes but without success. Can you please check this and discover what would be error in code?
Thank you.

There is no good nor evil, just decisions and consequences.
 
Hi,
if you only got 4 lines, I suspect an error in your code. Please upload.

Regards,

Jockey(2)
 
Hi,
if you only got 4 lines, I suspect an error in your code. Please upload.
Regards,
Jockey

I did it, I did it already!

There is no good nor evil, just decisions and consequences.
 
You didn't define local variables Local i,k,ke, therefore these get private variables and you influence them in calls, each running level of PrintComb must have it's own local seperated variables, the same goes for the parameters. Use LPARMETERS, not PARAMETERS.

If you debug you'd seen that when returning from a PrintComb call to the rest of a previous PrintComb call the loop variables are changed and thus the loop and program terminates too early.

You need to read chapters about variable scoping in foxpro.

Modificatios needed to your code are: LPARAMETERS and directly after the LPARAMETERS line put the variable declaration: Local i,k,ke

Bye, Olaf.
 
Actually DO WITH is another problem:

Code:
NumInSeq = 1
afunction(NumInSeq)
? NumInSeq

DO afunction WITH NumInSeq
? NumInSeq

PROCEDURE afunction ()
   lparameters p1
   p1 = p1 + 1
ENDPROC

With DO by default parameters are passed by reference, not by value, no matter if you define parameters with lparameters as local or with parameters as private.

So change calls of PrintComp to Printcomb(...) instead of Do PrintComb With ....

Bye, Olaf.
 
Oh, man Olaf... you saved rest of my week! Thank you a lot, I gave you just one star but in my eyes you deserve a sky full of stars. I'm I too generous? No, I'm just thankful for your valuable post and short lesson about "variable life and presence".
Honestly speaking, I'm not big fan of using procedures, so due that I was in trouble with it. Maybe foreign language is one of reason for it, but I hope it will change for better. Thanks for your explanation. God bless you pal.

There is no good nor evil, just decisions and consequences.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top