• Hi All

    Please note that at the Chandoo.org Forums there is Zero Tolerance to Spam

    Post Spam and you Will Be Deleted as a User

    Hui...

  • When starting a new post, to receive a quicker and more targeted answer, Please include a sample file in the initial post.

Finding the Nth negative value

BenefitRich

New Member
Hopefully the forum can help me since I've been struggling with this for a few days and am losing my mind.


I have a large range of automatically generated columns that report daily predicted inventory levels.

These numbers can be positive, negative, or 0.


Given a user supplied integer I need to find the StartDate of the Nth negative number range in the data as well as the last corresponding consecutive negative number.


Of course, this report has hundreds of lines of data, so if at all possible, an array formula / helper rows would best be avoided.


I have put an example file here: http://temp-share.com/show/FHKdPlm06 with data and expected outputs.


Thank You in advance!
 
Well, I can't afford too much time on this so i'll just go the simple helper lines method. I did it in a separate worksheet. each answer will need 2 support lines. so a total of 4 helper line per vendor.


For your B2 the formula is: INDEX(1:1,1,MATCH(A2,4:4,0))

where: E3 = IF(E2<0,IF(D2>=0,1,0),0) copy across to the right

where: E4 = SUM($E$3:E3) copy across to the right


for your C2 the formula is: INDEX(1:1,1,MATCH(A2,8:8,0))

Note: i removed your desired result table

where: E7 = IF(E2<0,IF(F2>=0,1,0),0) copy across to the right

where: E8 = IF(E7=0,0,SUM($E$7:E7)) copy across to the right


I have tested the formula and they match your desired answer. this is the quick and dirty version I can come up with. you can do this in a separate sheet and link the answer back to your Sheet 1.
 
Hi, BenefitRich!


Give a look at this file: https://skydrive.live.com/?cid=3a8bdc8cdf4d772c#!/view.aspx?cid=3A8BDC8CDF4D772C&resid=3A8BDC8CDF4D772C!268


Neither helper columns nor array formulas...

... but nothing is free: it uses a little piece of VBA code


The UDF vNegativeDate (user defined function) has 3 parameters:

- row data

- sequence order

- start ("S") or end ("E") date


Check if it's suitable for you.

Regards!


PS: the link ends in "...268", copy and paste, don't click (SkyDrive moods!)
 
hi SirJB7,


How does the worksheet update itself when say, AF2 is changed to a positive number? Given the large number of rows of vendors?
 
Thanks SirJB7! I guess I should have known that VB would be the way to go. I'll have to look at the code in greater depth and test it some, but I wanted to thank you! It is interesting to use a "S" or "E" as a switch. That's very smart and I would never think to construct the same function to cover both possibilities.
 
@Fred

Hí, the other night I was about to send you the following msg and the site went off.

-----

@Fred


Hi!


I'm very glad helping other people with their issues, and reading and learning every day with the solutions given or suggested to them. It's a two-way process, and it's nicer when it challenges you... frequently! I like it.


As someone once said "I know that I know nothing", and each day I reafirm that :)))

My nothing decreases every day but less than the target scope increment... so I'll be busy for a long time, I guess.


Very kind your comment, thank you very much.


Regards!

-----
 
@Fred

Hi!

Now that I'm re-reading carefully the post, it's missing my answer (Ctrl-Alt-F9 as a don't-know-why-but-it-works and a reference to my yet unclosed post http://chandoo.org/forums/topic/udf-lose-their-value-until-ctr-alt-f9) and your nice comment which originated my previous response.

Regards!
 
Hi, BenefitRich!


About your comment.

It's just a matter of practice, only requiring a regular dose of write, review, rewrite, update, erase, write again... and when you realize that are spending more time in other than writing, you begin to learn how to write... and that's the only secret.


About the code.

It doesn't require such a deep analysis, let me help you.


a)

[pre]
Code:
' constants
Const kiFirstColumn = 5
Const ksStart = "S"
Const ksEnd = "E"
Const kdDate0 = #1/1/1900#
Const ksError = "Error"
I hate hardcoding fixed values within the code, so it's more clear assigning a meaningful name.


b)

[pre][code]' declarations
Dim iColumn As Integer, iOrder As Integer, nValue As Single, nValueAnt As Single
Dim dDate As Date
The same for variables not defined or defined without type, so it aids to not to misuse or assume incorrect data.


c)

[pre][code]' start
iColumn = kiFirstColumn
nValueAnt = 0
dDate = kdDate0
iOrder = 0
[/pre]
iColumn: pointer to navigate thru the date & stock values

iOrder: occurrence number of negative sequence

nValue: stock for iColumn

nValueAnt: idem for previous (key for the process!!!)

dDate: date found


d)

' process
Do
' stock
nValue = Cells(plRow, iColumn).Value
' sequence
Select Case nValue
' from pos to neg
Case Is < 0
If nValueAnt >= 0 Then
If psStartEnd = ksStart Then
iOrder = iOrder + 1
If iOrder = piOrder Then dDate = Cells(1, iColumn).Value
End If
End If
' from neg to pos
Case Is >= 0
If nValueAnt < 0 Then
If psStartEnd = ksEnd Then
iOrder = iOrder + 1
If iOrder = piOrder Then dDate = Cells(1, iColumn - 1).Value
End If
End If
End Select
' cycle
nValueAnt = nValue
iColumn = iColumn + 1
Loop Until Cells(plRow, iColumn - 1).Offset(-1, 0).Value = "" Or _
iOrder = piOrder And dDate <> kdDate0[/code][/pre]
Here is the core.

For each stock value at current column, it only checks two cases:

1) change from positive to negative (used for the date start parameter)

2) change from negative to positive (used for the date end parameter)

If there's a hit, it increments iCounter.

Then it saves the actual stock value as previous in nValueAnt.

And loops moving one column right (here I had a problem with border conditions -as usual, not just me!-, so it checks not until last date column but first empty one, because of 2).


e)

' end
If dDate = kdDate0 Then
vNegativeDate = ksError
Else
vNegativeDate = dDate
End If[/code][/pre]
The easy part, returning the desired value. I used a variant type for the function, because you wanted to return a date or an error. And with this simple If, I avoid writing a more complicate formula in the worksheet, and multiple times, indeed:

Instead of "=vNegativeDate(2,$A17,"S")" it would have been necessary "=IF(vNegativeDate(2,$A17,"S")=DATE(1900,1,1),"Error",vNegativeDate(2,$A17,"S")".


And that's all. The only secret/smartness are those two little pieces of code within each case sentence.


Hope it helped you.

Regards!
 
Back
Top