excel match year and month in array - arrays

I have an array of dates in column a that i would like to match against on year and month.
A B C D E F G H I J
1 date name Name March April May June July August September
2 13-04-2016 Lars Lars 0 0 0 0 0 0 0
3 04-03-2016 Brian Brian 0 0 0 0 0 0 0
4 01-01-2016 Lars Erik 0 0 0 0 0 0 0
5 10-06-2016 Erik Knut 0 0 0 0 0 0 0
6 31-07-2016 Erik Soren 0 0 0 0 0 0 0
I have tried with $A:$A;"="&DATE(YEAR(TODAY());3;""); where ;3; is the month of march. It evaluates to 0 on all accounts.
So how to adapt to make it count the number of dates matching the Year and Month (D2) for Lars (C2) in A:A?
Anyone.

One way to do this is to convert the date to text, then evaluate that in your formula.
Logic:
If Monthname(Date) = Top Row, then 1, else 0
Formula (placed in cell D2):
=if(text($A1,"mmmm")=D$1,1,0)
I have used the relative references for clicking and dragging.

Put this in D2 (and adapt as needed)
=IF(DATE(YEAR(TODAY()),3,1)=DATE(YEAR(A3),MONTH(A3),1),1,0)
=IF( --Start the if
DATE(YEAR(TODAY()),3,1) -- Current year, 3rd month, 1st day
= --Equals (for if statement)
DATE(YEAR(A3),MONTH(A3),1) -- Year & month from Cell A3 & 1st day
,1,0) -- Print '1' if true else print '0'

Related

Repeat rows based on item count for each row and assign values for repeated rows

I have a df with the item and it is available in different rooms
Item Room1 Room2 Room3 Room4
Ball 1 1 1 0
Bat 1 1 1 1
Wicket 1 1 1 0
Now I want to repeat the rows based on item counts on different Rooms. For example for Item - Ball there are three 1's in Room1, Room2, Room3 so need to repeat 3 rows with assigning 0 in each row only for Room1, Room2, Room3 columns, and Room4 is not considered for Item Ball and it can be 0's for all Ball item rows. There are 300 columns with different room names, for example Room1,room2,room3,room4,BlockArea1,Block2 etc.Below is the expected output
Item Room1 Room2 Room3 Room4
Ball 1 1 1 0
Ball 1 0 1 0
Ball 1 1 0 0
Bat 1 1 1 1
Bat 1 1 1 0
Bat 1 1 0 1
Bat 1 0 1 1
Wicket 1 1 1 0
Wicket 1 0 1 0
Wicket 1 1 0 0
Any help would be appreciated
To have a more interesting example, with a source row containing 0
somewhere else than in the last column, I created df as:
Item Room1 Room2 Room3 Room4
0 Ball 1 1 1 0
1 Bat 1 1 1 1
2 Wicket 1 1 1 0
3 Xxxx 0 1 1 1
The first step is to define a function to process each row:
def rowProc(row):
n = 0
res = []
for idx, val in row[row > 0].items():
outRow = row.copy()
if n > 0:
outRow[idx] = 0
res.append(outRow)
n += 1
return pd.DataFrame(res)
An important project detail is that the source row comes here from
a bit "changed" DataFrame, namely Item column will be set as
the index. So the only processed columns are "further" (Room...)
columns.
For the current row it generates a DataFrame containing:
as many rows as how many ones contains the source row,
the first output row is an exact copy of the source row (like in
your expected result),
further rows have consecutive ones set to 0.
Then run:
result = pd.concat(df.set_index('Item').apply(rowProc, axis=1).tolist())
result.index.name = 'Item'
result.reset_index(inplace=True)
The result is:
Item Room1 Room2 Room3 Room4
0 Ball 1 1 1 0
1 Ball 1 0 1 0
2 Ball 1 1 0 0
3 Bat 1 1 1 1
4 Bat 1 0 1 1
5 Bat 1 1 0 1
6 Bat 1 1 1 0
7 Wicket 1 1 1 0
8 Wicket 1 0 1 0
9 Wicket 1 1 0 0
10 Xxxx 0 1 1 1
11 Xxxx 0 1 0 1
12 Xxxx 0 1 1 0

Summing across SAS arrays based on intervals i.e. start date and end date

I am trying to sum variables in an array based on start and end date. For each ID there is one row (if the start and end date are within the same year), two rows (if the start and end date are within consecutive years) or multiple rows for different periods of start and end dates. There are 12 variables with counts for each month i.e. v1-v12 where v1 is january and v12 is december. The two rows for some ID contain monthly values for the 2 consecutive years i.e. within the stat year and the end year. I am trying to get the sum count for the array variables but only from the start date to the end date for each ID. For example, for ID 1 the start date is 07/23/2007 and end date is 06/07/2008, i would like to sum from V7 (july start month) to v12 in 2007 and V1 to V6 (june end month) in 2008 i.e. second row. Here's what I have:
ID STARTDATE ENDDATE YR V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12
1 07/23/2007 06/07/2008 2007 3 5 2 6 3 2 1 3 4 1 2 3
1 07/23/2007 06/07/2008 2008 0 4 2 2 3 0 1 3 1 0 2 3
2 02/01/2002 07/27/2002 2002 1 0 2 3 1 0 1 2 3 0 0 2
3 05/26/2008 03/07/2009 2008 2 0 2 3 1 2 1 1 3 0 0 1
3 05/26/2008 03/07/2009 2009 4 1 4 3 1 0 2 3 3 1 0 3
3 10/17/2011 08/17/2012 2011 3 3 0 1 0 1 1 5 3 1 0 1
3 10/17/2011 08/17/2012 2012 1 3 2 3 1 0 1 2 3 2 0 2
4 02/27/2004 01/22/2005 2004 2 0 2 3 1 2 1 1 3 0 0 1
4 02/27/2004 01/22/2005 2005 0 4 2 2 3 0 1 3 1 0 2 3
and this is what I want :
ID STARTDATE ENDDATE YR V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12 sum
1 07/23/2007 06/07/2008 2007 3 5 2 6 3 2 [1 3 4 1 2 3] 25
1 07/23/2007 06/07/2008 2008 [0 4 2 2 3 0] 1 3 1 0 2 3 25
2 02/01/2002 07/27/2002 2002 1 [0 2 3 1 0 1] 2 3 0 0 2 8
3 05/26/2008 03/07/2009 2008 2 0 2 3 [1 2 1 1 3 0 0 1] 18
3 05/26/2008 03/07/2009 2009 [4 1 4] 3 1 0 2 3 3 1 0 3 18
3 10/17/2011 08/17/2012 2011 3 3 0 1 0 1 1 5 3 [1 0 1] 15
3 10/17/2011 08/17/2012 2011 [1 3 2 3 1 0 1 2] 3 2 0 2 15
4 02/27/2004 01/22/2005 2004 2 [0 2 3 1 2 1 1 3 0 0 1] 14
4 02/27/2004 01/22/2005 2005 [0] 4 2 2 3 0 1 3 1 0 2 3 14
Here's the code I tried
data want;
set have;
array vars(*) V1-V12;
DT_CHECK=intnx('month',ENDDATE,-12);
start=intck('month','STARTDATE,DT_CHECK)+1;
if start<1 then do;
error 'Start date out of range';
delete;
end;
else if start>dim(vars)-12 then do;
error 'End date out of range';
delete;
end;
do _N_=start to start+12;
sum_n+vars(_N_);
end;
format DT_CHECK mmddyy10.;
run;
But am having problems. Any help is appreciated. Thank you.
A DOW / serial loop technique can compute a value for criteria over a group, and then apply that value to each row in group.
Example:
Requires the start to end date intervals within an id be mutually exclusive (i.e. do not overlap and data are sorted by id startdate enddate)
data want;
* [sum] variable is implicitly reset to missing at the top of the step.;
do _n_ = 1 by 1 until (last.enddate);
set have;
by id startdate enddate;
array v(12);
_month1 = intnx('month', startdate, 0);
_month2 = intnx('month', enddate, 0);
do _index = 1 to 12;
if _month1 <= mdy(_index,1,yr) <= _month2 then sum = sum(sum,v(_index));
end;
end;
do _n_ = 1 to _n_;
set have;
output;
end;
format sum 4.;
drop _:;
run;
The answer does not address the scenario of startdate to enddate intervals that overlap within an id.
Since each observation represents one year a straight forward approach would be to just loop month from Jan to Dec and check if that month falls within your date range.
data want;
do until(last.startdate);
set have;
by id startdate;
array v v1-v12;
do month=1 to 12 ;
if intnx('month',startdate,0,'b')<=mdy(month,1,yr)<=intnx('month',enddate,0,'e')
then sum=sum(sum,v[month])
;
end;
end;
keep id startdate enddate sum;
run;
Results:
Obs ID STARTDATE ENDDATE sum
1 1 2007-07-23 2008-06-07 25
2 2 2002-02-01 2002-07-27 7
3 3 2008-05-26 2009-03-07 18
4 3 2011-10-17 2012-08-17 15
5 4 2004-02-27 2005-01-22 14

total days in Arrears calculation

guys i have problem with one old SP which calculates total days late when the costumer is late with the payments of an instalment
it goes like this:
#total days paid# #1st inst days due# #2nd inst days due# #total days#
---------------------------------------------------------------------------
---------------------------------------------------------------------------
0 1 0 1
0 2 0 2
0 3 0 3
0 4 0 4
0 30 0 30
0 31 1 31
0 32 2 32
32 0 3 35
so the procedure calculates (total days paid) + max of the days due
0+32 =32
32+3 =35
etc
and makes mistakes whenever the costumer is latemore then 30 days
its should always increment by 1 and not overlap the calculations
can anyone think of a quick way to fix this without over writhing the whole thing
so you have an existing formula for calculating #total days#, if you can locate the final place where that is returned, it could be a formula or a field name, let's call that (...) because we don't know what it is here, you can change it to
(...) + CASE WHEN (...) >= 30 THEN 1 ELSE 0 END AS '#total days#'

MS SQL Table of CRON Future Runs

I have a need to create a table/view containing a full and complete list of future CRON executions for a period of time, e.g. from 12 months ago to 12 months in the future.
My source data is in MS SQL 2012 and contains the following sample information;
TASK SCHEDULE SCHEDULESTART SCHEDULEEND
T1 0 0 0 ? * MON 2015-04-08 16:15:09.557 2015-04-20 00:00:00.000
T2 0 0 0 ? * MON 2015-05-22 15:56:48.140 2015-07-27 00:00:00.000
T3 0 0/56 * * * ? 2015-06-25 10:17:07.387 2015-06-25 15:00:00.000
T4 0 10/15 21 3,19 5-9 ? 2015-06-25 10:18:48.077 2015-08-28 10:17:15.000
Unfortunately as MS SQL doesn't support/contain a JVM, I'm limited (I think) to programmatically breaking this out into it's components parts.
I've managed to break out he parts of the expression with the following;
;WITH cte (SCHEDULE,SCHEDULESTART,SCHEDULEEND,SCHED_Attributes)
AS
(
SELECT SCHEDULE,SCHEDULESTART,SCHEDULEEND,
CONVERT(XML,'<Product><Attribute>'
+ REPLACE([SCHEDULE],' ', '</Attribute><Attribute>')
+ '</Attribute></Product>') AS SCHED_Attributes
FROM USCH_TASK
)
SELECT
SCHEDULE,SCHEDULESTART,SCHEDULEEND,
SCHED_Attributes.value('/Product[1]/Attribute[1]','varchar(25)') AS sched_seconds,
SCHED_Attributes.value('/Product[1]/Attribute[2]','varchar(25)') AS sched_minutes,
SCHED_Attributes.value('/Product[1]/Attribute[3]','varchar(25)') AS sched_hours,
SCHED_Attributes.value('/Product[1]/Attribute[4]','varchar(25)') AS sched_day_of_month,
SCHED_Attributes.value('/Product[1]/Attribute[5]','varchar(25)') AS sched_month,
SCHED_Attributes.value('/Product[1]/Attribute[6]','varchar(25)') AS sched_day_of_week,
SCHED_Attributes.value('/Product[1]/Attribute[7]','varchar(25)') AS sched_year
from cte
This results in (for example)
sched_seconds sched_minutes sched_hours sched_day_of_month sched_month sched_day_of_week sched_year
0 0 0 ? * MON NULL
0 0 0 ? * MON NULL
0 0/56 * * * ? NULL
0 10/15 21 3,19 5-9 ? NULL
Main thrust of this question is then how to handle the component parts of this, * and ? are easy enough, ranges (e.g. 5-9 or MON-THU) are pretty OK, but am struggling with how to determine where have specific dates/months (e.g. 3,19) or more complex configurations (such as the last example above or days of month ="1-3,6-7,15")
CASE
WHEN CHARINDEX('*',Prod_Attributes.value('/Product[1]/Attribute[6]','varchar(25)')) > 0 THEN 'Y'
WHEN CHARINDEX('?',Prod_Attributes.value('/Product[1]/Attribute[6]','varchar(25)')) > 0 THEN 'Y'
WHEN CHARINDEX('MON',Prod_Attributes.value('/Product[1]/Attribute[6]','varchar(25)')) > 0 THEN 'Y'
WHEN CHARINDEX('SUN-TUE',Prod_Attributes.value('/Product[1]/Attribute[6]','varchar(25)')) > 0 THEN 'Y'
WHEN CHARINDEX('SUN-WED',Prod_Attributes.value('/Product[1]/Attribute[6]','varchar(25)')) > 0 THEN 'Y'
WHEN CHARINDEX('SUN-THU',Prod_Attributes.value('/Product[1]/Attribute[6]','varchar(25)')) > 0 THEN 'Y'
WHEN CHARINDEX('SUN-FRI',Prod_Attributes.value('/Product[1]/Attribute[6]','varchar(25)')) > 0 THEN 'Y'
WHEN CHARINDEX('SUN-SAT',Prod_Attributes.value('/Product[1]/Attribute[6]','varchar(25)')) > 0 THEN 'Y'
ELSE 'N'
END as DOWMon
However this approach wouldn't work for day 1 of the month as the code
WHEN CHARINDEX('1',Prod_Attributes.value('/Product[1]/Attribute[4]','varchar(25)')) > 0 THEN 'Y'
would also find value 10 through 19, 21 and 31!
Any tips or tricks are gratefully received!
Andy

VBA function to iterate through cells, replacing a cell with the relative column header value

I'm trying to convert a data matrix to a new standard that should fit a specific analysis software.
The initial matrix looks like this:
real char num 10 10 25 26 26 56
--------------------------------
state num 1 2 9 4 6 3
--------------------------------
name 1 0 0 1 1 0 1
name 2 1 0 0 0 0 0
name 3 0 1 1 0 0 1
name 4 0 1 0 0 1 0
name 5 1 0 0 0 0 0
name 6 0 0 1 0 1 0
I've been trying to achieve this:
real char num 10 10 25 26 26 56
--------------------------------
state num 1 2 9 4 6 3
--------------------------------
name 1 0 0 9 4 0 3
name 2 1 0 0 0 0 0
name 3 0 2 9 0 0 3
name 4 0 2 0 0 6 0
name 5 1 0 0 0 0 0
name 6 0 0 9 0 6 0
Essentially, what I'm trying to do is:
1. For every column, look in every cell for a number other than 0;
2. If this condition is achieved, replace the cell value with the relative "state" header. Meaning, for instance, if A4 <> 0, then replace it with A3 value.
The code I've used is as follows:
Sub Iterate_replace()
Sheets("matrix").Select
Dim r As Range, cell As Range, state As Range
Set r = Range("C3")
Set state = Range("C2")
For Each cell In r
If cell.Value <> "0" Then
cell.Value = state.Value
End If
Next
End Sub
It works fine in a defined range of one single column, but I'm having trouble making it dynamic. Should I use R1C1 notation to refer to the cells in the range? Everything related that I could find never explicits how to make this iteration more flexible. Should I use nested loops? Loops are a very difficult thing for me to grasp, still, so, please be patient.
I'd appreciate if anyone could point me to the right direction. Thanks!
I am assuming that there is nothing else on each sheet than the matrix in question. In that case you should be able to make you procedure dynamic by modifying your code like the following:
Sub Iterate_replace()
Sheets("matrix").Select
Dim i As Integer, j As Integer
Dim state As Range
Set state = Range("C2")
'Loops through each row and each column in matrix
For i = state.Column To ActiveSheet.Cells(state.Row, Columns.Count).End(xlToLeft).Column
For j = state.Row + 1 To ActiveSheet.Cells(Rows.Count, state.Column).End(xlUp).Row
If Cells(j, i).Value <> 0 Then
Cells(j, i).Value = Cells(state.Row, i).Value
End If
Next j
Next i
End Sub
This will loop through each column and each row in your matrix if you have defined in what cell the most left state value is located.

Resources