array from continuous data? - excel

I have a quite difficult problem that i cant wrap my head around.. hope you can help me!
Lets say my data is in A1:G1 for example:
A1 B1 C1 D1 E1 F1 G1
X X 0 X X X 0
or
Y X X X X Z X
The thing i would need to come up with is how to get array from this data according to the X, BUT if like in example 1 there is 2 times X in the beginning and 3 x next to each other so the array should come out like {2;2;0;3;3;3;0} so i want the array to be 7 long and the array should show the x as number how many are next to each other.
example 2 should come out like {0;4;4;4;4;0;1}
if you can figure this out would really help me alot!
Edit:
Trying to give out better, more bigger picture of what i mean..
if data is :
A B C
1 X X
2 X X
3 X
it should come out as
A B C
1: 2 4 0
2: 0 4 2
3: 1 0 0
or in array {2\4\0;0\4\2;1\0\0}
on B1 and B2 there should be 4 because the formula should count horizontal but also vertical continuum. I tried to use usmanhaqs formula but i was not able to modify it so the count resets on every line.
Real size of the table is 7 times 7 cells.
I will use the array with another array (scoreboard which is also 7 times 7 cells, and has numbers 1, 2 or 3 on every cell) using sumproduct and it will give out the points of that player.
I appreciate your efforts on helping out a newbie learner on vba :)

For a formula solution, I can only come up with one for the special case where you have just X's and zeroes (example 1) so far:
=SUM(IF(A1:G1<>"X",0,INDEX(FREQUENCY(IF(A1:G1="X",COLUMN(A1:G1)),IF(A1:G1<>"X",COLUMN(A1:G1))),N(IF({1},SUBTOTAL(2,OFFSET(A1,0,0,1,COLUMN(A1:G1)))))+1,1)))
entered as an array formula using CtrlShiftEnter
I have wrapped it in a SUM function to demonstrate that it generates an array which can be passed to another function (result: 13) or it can be array-entered across several cells:

You can test this code
Function get_array(r As Range, match_chr As String)
Dim check_val
Dim array_value
array_value = "{"
For i = 1 To r.Count
check_value = r.Item(i)
If (check_value = match_chr) Then
j = i + 1
Do While (j <= r.Count) And (check_value = r.Item(j))
j = j + 1
Loop
array_value = array_value & WorksheetFunction.Rept(j - i & ", ", j - i)
i = j - 1
Else
array_value = array_value & "0, "
End If
Next
array_value = Left(array_value, Len(array_value) - 2) & "}"
get_array = array_value
End Function
You can use it as below
EDIT
find below another function to return an array of values that can be used in the formulae
Function get_number_array(r As Range, match_chr As String)
Dim check_val
Dim array_value
Dim number_array(1 To 50) As Long
For i = 1 To r.Count
check_value = r.Item(i)
If (check_value = match_chr) Then
j = i + 1
Do While (j <= r.Count) And (check_value = r.Item(j))
j = j + 1
Loop
For k = 1 To j - i
number_array(i + k - 1) = j - i
Next k
i = j - 1
Else
number_array(i) = 0
End If
Next
get_number_array = number_array
End Function
You have to use it same as the previous one, but it will return excel array.

Related

Pick (5) numbers and (1) modified numbers from a list and print the sum from those numbers that meets a specified range in VBA

I was trying to do the following using Excel VBA:
[1] 30 numbers (Input manually in Excel)
[2] Pick 1 number from [1] and x 1.5
[3] Pick another 5 numbers from [1]
[4] Sum all values from [2] and [3]
[5] Define a min and max range for the sum
[6] Print out all the sum from [4] that meet range [5]
I was creating an array of the 30 numbers, create a loop of each element, eliminate that element in the array so it would not double count and sum it up. However, I'm not sure what is the logic of this should be to incorporate the value from [2].
I suggest a slightly different process:
Create your array of 30 numbers
Randomly select 6 numbers from that array
multiply the first of the 6 numbers by 1.5
etc. as you have specified.
EDIT: Example code below:
Sub PickSixNumbers()
'Set variables:
Dim lBigArray(1 To 30) As Variant, lSmallArray(1 To 6) As Long
'Putting some fake values in here, over to you to fix this bit:
For a = 1 To 30
lBigArray(a) = a
Next
'Pick your numbers:
a = 1
Do Until a > 6
lSmallArray(a) = lBigArray(RndIntegerBetween(1, 30))
'If the selected number has already been selected, don't move to the next one
If CountInArray(lSmallArray, lSmallArray(a)) = 1 Then a = a + 1
Loop
'Multiply the first one by 1.5
lSmallArray(1) = lSmallArray(1) * 1.5
If WorksheetFunction.Sum(lSmallArray) > 0 And WorksheetFunction.Sum(lSmallArray) < 100 Then
Debug.Print "Sum is between 0 and 100"
Else
Debug.Print "Sum is not between 0 and 100"
Debug.Print "SHOCK HORROR"
End If
End Sub
'Helper Functions:
Function CountInArray(arr() As Long, Value As Long) As Long
CountInArray = 0
For a = LBound(arr) To UBound(arr)
If arr(a) = Value Then CountInArray = CountInArray + 1
Next
End Function
Function RndIntegerBetween(Min As Long, Max As Long) As Long
RndIntegerBetween = Int((Max - Min + 1) * Rnd + Min)
End Function

Excel formula for trend?

does any one can suggest me any formula in excel to use for following question.
I have a data list with historical numbers for each particular example. I would need in column G Categoraise in 3 Categories Increasing, Decreasing, Various:
For exmaple
Column A Column B Column C Column D Column E Column F Column G
month 1 month2 month3 month4 month5 Category
Example 1 3 1 2 0 4 Various
Example 2 6 4 3 1 0 Decreasing
Example 3 0 0 3 5 10 Increasing
I am not sure that trend focmula is a correct one.
Any kind suggestion?
Use nested IFS with SUMPRODUCT:
=IF(AND(SUMPRODUCT(--(B2:E2<C2:F2)),SUMPRODUCT(--(B2:E2>C2:F2))),"Various",IF(SUMPRODUCT(--(B2:E2<C2:F2)),"increasing",IF(SUMPRODUCT(--(B2:E2>C2:F2)),"decreasing","even")))
Here is a VBA solution which can be used directly on the worksheet:
Function ClassifySequence(nums As Range) As String
Dim i As Long, minDelta As Long, maxDelta As Long
Dim delta As Variant
With Application.WorksheetFunction
maxDelta = .Min(nums) - .Max(nums)
minDelta = -maxDelta
End With
For i = 1 To nums.Cells.Count - 1
delta = nums.Cells(i + 1).Value - nums.Cells(i).Value
If delta < minDelta Then minDelta = delta
If delta > maxDelta Then maxDelta = delta
Next i
If maxDelta <= 0 Then
ClassifySequence = "Decreasing"
ElseIf minDelta >= 0 Then
ClassifySequence = "Increasing"
Else
ClassifySequence = "Various"
End If
End Function
For example,
In this code I decided to classify a constant sequence as decreasing. That could of course be changed, either to "Various" or "Increasing" or by creating a fourth category as in Scott Craner's excellent answer.

Table with 4 variable columns

I'm sure this is simple for all of you, but I'm new here. How do I create a formula or code that can output all of the potential scenarios for this type of array below? Basically, max is 60, min is 0, but I'm unsure how to make Excel spit out a table that represents this.
Solution:
Doing it with Excel formulas alone, while theoretically possible, is incredibly computationally demanding and crashed Excel when I was trying to do so. You can do this fairly easy with VBA though.
Create a VBA module, drop these two snippets in, press play, and wait for a few seconds to a minute while the code runs. The code is not the most efficient, but it is probably the simplest algorithm to understand.
Public Sub comb4()
Dim a, b, c, d, n, r, x As Integer
x = 60
a = x
Do While a >= n
b = x - a
Do While b >= n
c = x - a - b
Do While c >= n
d = x - a - b - c
Do While d >= n
If sumToZero(-x, a, b, c, d) Then
r = r + 1
Cells(r, 1).Value = a
Cells(r, 2).Value = b
Cells(r, 3).Value = c
Cells(r, 4).Value = d
End If
d = d - 1
Loop
c = c - 1
Loop
b = b - 1
Loop
a = a - 1
Loop
End Sub
Public Function sumToZero(ParamArray intNums())
For x = LBound(intNums) To UBound(intNums)
y = y + intNums(x)
Next x
If y = 0 Then sumToZero = True
End Function
Code explanation:
x is the max that you defined, while n is the min you defined.
r is a counter which helps us track what row to print to.
Since we always want to count down to 0 for each column's sub-permutations, each of our Do While loops will count from the theoretical maximum value down to 0.
The loop structure is nested so that each time we hit -1 in a column N we instead leave the loop, go into the loop one level higher, and decrease the value in column M by 1. The value in N is reset when we start the next instance of the loop for M.
Between each value change we need to check to see if the result is a valid solution. We pass the (negative) max and all 4 variables we are looping to a function which sums the values and returns true if the variables are equal to the max. When the function is true, we go to the next row in Excel and print the four values.

Auto-increment based on other column repeats

I need a macro or formula that can do this:
Column A Values:
1
1
1
2
2
2
3
3
4
4
4
5
5
6
6
I need Column B to do:
1
2
3
1
2
3
1
2
1
2
3
1
2
1
2
Because column B has to have an increment number while column A has the same repeated value (for example 1 1 1 2), when it changes (to 2 or 3 etc.) the counter on column B has to reset and increment itself while A repeats the next value (1 2 3 1)
Thanks
Edit
Have a look at bzimor's answer as he solves is in a more general way without a hard value in column B1!
Original Answer
You can solve it the following way without VBA:
Put a hard value of 1 in column B1. This is your start value and should be always correct because you start counting with 1.
Then enter the following formula in B2
=IF($A2=$A1;$B1+1;1)
Just drag the formula down to the other rows of B and you're done
So B3 should look like this
=IF($A3=$A2;$B2+1;1)
and so on ...
You can use single formula:
=COUNTIF($A$1:A1,A1)
Put it into cell B1 and fill down
Here is your desired macros
Sub jkjainGenerateSerialNumber20161124()
readcol = Val(InputBox("type ref col#"))
writecol = Val(InputBox("type dest col#"))
ts = 0
Range("A1000000").Select
Selection.End(xlUp).Select
lastrow = ActiveCell.Row
For n = 2 To lastrow
prev = Cells(n - 1, readcol)
curr = Cells(n, readcol)
If prev <> curr Then
ts = 1
End If
If prev = curr Then
ts = ts + 1
End If
Cells(n, writecol) = ts
Next
End Sub

Need a better algorithm ( Occurence of time)

The "B" column has occurence of time in it.Like these
A B
X4T00289 8/4/2011 3:12:07 AM
X4T00289 8/4/2011 3:15:07 AM
X4T00289 8/4/2011 3:18:20 AM
X4T00290 8/4/2011 3:12:37 PM
YCE00194 8/8/2011 5:12:17 AM
YCE00194 8/8/2011 5:14:07 AM
YCE00194 8/10/2011 10:12:06 PM
YCE00194 8/10/2011 10:15:16 AM
Z4W00109 8/12/2011 11:12:22 AM
Z4W00109 8/4/2011 11:58:07 AM
Z4W00109 8/4/2011 12:00:07 PM
I have taken a variant and dumped the range in it like these
var = activesheet.range("A1:B4000").value
QUESTION:
The problem is, I have to identify the consequent rows that has same ID in column A and which occured within 5 minutes and highlight them with color.Take a look at first 2 rows, They occured within 5 minutes and column A value is same for both but the 3rd row occurred after 5 minutes when compared to the first row, So that row should be ignored when highlighting .While coming back to the last 2 rows they also occured within 5 minutes, they should be highlghted with color as they occured within5 minutes. I think you got what i wanted to do. Any questions please comment and I will explain it more cleaner way.
MY APPROACH:
This is what i have tried
, I have used splitting some thing like these
temp = split(text," ")
and then compare temp(0) and temp(1) and temp(2) with consequent rows
temp(0) it has year date and month in it
temp(1) it has Time
temp(2) it has AM or PM
if temp(2) and temp(0) are equal for conesequent rows then this piece of code executes
temp_var=split(temp(1),":") again
again temp_var has temp_var(0)=hours temp_var(1)=minutes temp_var=seconds
Now I have to check hours if hours are equal then
I have to check for minutes like
(minutes - next row minutes) <= 5 then color it
This is what I have done.Im not getting any more better ideas to do it. I guess there might be some other easiest way in do it. may be some inbuilt functions which im not aware of So Let me know is this the only better way to do or any other better approach or algorithm to do it? like faster way to do it?Please help me with this
This is the Code you need, if you need any clarification or change comment here
Sub HighlightDiff()
Dim r As Integer
Dim i As Integer
Dim diff As Integer
Dim y As Integer
Dim m As Integer
Dim d As Integer
Dim h As Integer
r = 4000 ' Total No. of rows
For i = 1 To r
If (Trim(Cells(i, 1).Value) = Trim(Cells(i + 1, 1).Value)) Then
'd = Cells(i, 2).Value - Cells(i + 1, 2).Value
y = Year(Sheet1.Cells(i, 2)) - Year(Sheet1.Cells(i + 1, 2))
m = Month(Sheet1.Cells(i, 2)) - Month(Sheet1.Cells(i + 1, 2))
d = Day(Sheet1.Cells(i, 2)) - Day(Sheet1.Cells(i + 1, 2))
'h = Hour(Sheet1.Cells(i, 2)) - Hour(Sheet1.Cells(i + 1, 2))
If ((y + m + d) = 0) Then
diff = (Hour(Sheet1.Cells(i, 2)) * 60 + Minute(Sheet1.Cells(i, 2))) -
(Hour(Sheet1.Cells(i + 1, 2)) * 60 + Minute(Sheet1.Cells(i + 1, 2)))
If (diff > -5 And diff < 5) Then
Range(Cells(i, 1), Cells(i, 2)).Interior.ColorIndex = 3
End If
End If
End If
Next i
End Sub
here is the algorithm:
for each c in col B
minTime = MIN(col b where ref = current ref)
if c-minTime < 5 min then
change background
end if
next c
Note that you can get dateTime difference simply like this:
if range("onecell")-range("anothercell") < #00:05#
First off, it would be good to ensure that your datetime values in column B are formatted correctly. To do this:
Select all values in column B
Now press CTRL + 1
Select Custom and type in dd/mm/yyyy hh:mm:ss AM/PM
Now you can use the following code to loop through all id's in column A and highlight in red which ones have the same id and are within 5 mins of each other:
Sub WithinFiveMinutes()
Dim rngID As Range, id As Range, timeDiff As Long
Set rngID = Range("A1:A11") //Change for your id list e.g. A1:A4000
For Each id In rngID
If id = id.Offset(1, 0) Then
timeDiff = DateDiff("n", CDate(id.Offset(0, 1)), CDate(id.Offset(1, 1))) //"n" gives time difference in minutes...
If timeDiff >= -5 And timeDiff <= 5 Then
Range(id, id.Offset(0, 1)).Interior.ColorIndex = 3
Range(id.Offset(1, 0), id.Offset(1, 1)).Interior.ColorIndex = 3
End If
End If
Next id
End Sub

Resources