Excel macro for changing ID value's - excel

For example:
695678 needs to be 1
695678 needs to be 1
695678 needs to be 1
695678 needs to be 1
695683 needs to be 2
695683 needs to be 2
695683 needs to be 2
696217 needs to be 3
696217 needs to be 3
I got this list of ID's (every number corresponds to a person) However these numbers for example 695678, 695683, 696217 don't go up by one. They are all ranked from low to high. Is there a way to automatically change these values to 1,2,3,... and so on by changing the lowest value to 1 and the second lowest value to 2 and so on. (can't figure out how to do it with macro's)
One note is that the IDs are repeated as these people made more then one transaction.
thanks!

If you require a VBA solution, then:
Sub Renumber()
Dim N As Long, I As Long, OldValue As Long
Dim K As Long
K = 1
N = Cells(Rows.Count, "A").End(xlUp).Row
OldValue = Cells(1, 1).Value
For I = 1 To N
If Cells(I, 1).Value = OldValue Then
Cells(I, 1).Value = K
Else
OldValue = Cells(I, 1).Value
K = K + 1
Cells(I, 1) = K
End If
Next I
End Sub

#Gary's Student, your solution close to perfect, I've looked into this and added a small correction, Compiling it gives an runtime error, your K value is 1 and in your else clause it just takes the same value again.
After adjusting it to their excel file it worked perfect:
Sub Renumber()
Dim N As Long, I As Long, OldValue As Long
Dim K As Long
K = 1
N = Cells(Rows.Count, 2).End(xlUp).Row
OldValue = Cells(2, 2).Value
For I = 2 To N
If Cells(I, 2).Value = OldValue Then
Cells(I, 2).Value = K
Else
OldValue = Cells(**I + 1**, 2).Value
K = K + 1
Cells(I, 2) = K
End If
Next I
End Sub
The I + 1 between ** is the part that bugged.
I've also changed the cell indexes accordingly.
Kind regards,
David

Please try:
=IF(ISBLANK(A1),1,IF(A1=A2,B1,B1+1))
copied down to suit (with a blank in the top row of data).
To try to clarify, assumes data is in ColumnA but starting in A2 (A1 and B1 being blank), that the formula above is placed in B2 and copied down to suit.
First the test is whether A1 is blank (if True, returns 1 the start point - though this could be keyed into B2 and a simpler formula then used in B3 and so on). If A1 is not blank then there is a further test, whether or not the value has changed. If it has not (True), then use the value immediately above, if it has changed (False) use the value immediately above incremented by one.

Another formula incase your data ever needs to be unsorted, and should be faster then any Macros:
=SUMPRODUCT( (FREQUENCY($A$1:$A$9, $A$1:$A$9) > 0) * (A1 >= $A$1:$A$10) )

Related

Excel Matrix Assignment by Referring to a Cell

I am trying to construct a 2x2 matrix dependent on values in some cells (say B1). The code shall take the reference and make some mathematical manipulations, then assign this value to a new cell.
Sub matrix2()
Dim matrix(1 To 2, 1 To 2) As String
k1 = Cells(1, 2).Value
For i = 1 To 2
For j = 1 To 2
k = (-1) ^ (i + j)
matrix(i, j) = "=B1*" & k
Next j
Next i
Range("D1:E2") = matrix
End Sub
In the end, I get what I want but I need to go to each cell and press Enter to convert them in a real value. What I should get here is a matrix dependent on the value in B1. When I change B1, the values in the matrix will automatically change.
Is there any way to make it happen more easily? Because, I will be dealing with 40x40 matrices in the end, and I don't want to go over 1600 cells and press Enter.
I doubt this is going to be helpfull right now, but maybe in the (near) future. With the new MAKEARRAY() function you could do this outside of VBA with relative ease:
Formula in D3:
=MAKEARRAY(2,2,LAMBDA(i,j,B1*(-1^(i+j))))
You have to use a variant-array - not a string-array
Try this:
Sub Matrix2()
Dim arr(1 To 2, 1 To 2) as Variant 'instead of String
k1 = Cells(1, 2).Value
For i = 1 To 2
For j = 1 To 2
k = (-1) ^ (i + j)
arr(i, j) = "=B1*" & k
Next
Next
ActiveSheet.Cells(8, 1).Resize(2, 2).Formula = arr
end sub

Excel help - IF data in specific range of cells, THEN return column titles in same cell

I have a table with several week ending dates at the top of each column. I want to search a row for any column with data in and then return, in a list, all the column titles that had data in.
I have attached a picture to better show what I mean, in the picture I have simply typed the dates in. I would like a formula, maybe VBA? that can do this for me but its proving more difficult than I thought.
What final result should look like
Really appreciate any help!
Thanks
** edit: I have found a formula which works but will be incredibly long. Surely there is a way to combine and shorten?
=IF(C5<>0,TEXT(C1,"dd/mm")&" | ","")&IF(D5<>0,TEXT(D1,"dd/mm")&" | ","")&IF(E5<>0,TEXT(E1,"dd/mm"),"")
The above code only works in 3 columns too... Not the required 60 plus!
Paste this code into a module, and in cell B2 type =IFERROR(getNonBlankCells($C$1:$K$1,C2:K2),"") and drag it down to B5.
Function getNonBlankCells(Rng1 As Range, Rng2 As Range) As Variant
Dim i As Integer, j As Integer, n As Integer, test As String
Dim A As Variant, B As Variant, ret(), newret(), t As Integer, p As Integer
n = Rng1.Columns.Count
ReDim ret(1 To n, 0)
A = Rng1.Value2
B = Rng2.Value2
i = 1
For j = 1 To n
If B(1, j) <> "" Then
ret(i, 0) = A(1, j)
i = i + 1
End If
Next j
ReDim newret(LBound(ret) To UBound(ret))
For t = LBound(ret) To UBound(ret)
If ret(t, 0) <> "" Then
p = p + 1
newret(p) = ret(t, 0)
End If
Next t
ReDim Preserve newret(LBound(newret) To p)
getNonBlankCells = Join(newret, ", ")
End Function

Find the cell that is closest to a certain value in Excel

In Excel, I have many products with different sizes listed in columns, such that the sizes "10x10 cm", "11x11 cm" and "15x15 cm" belongs to Product A, etc.
In some other cells, I am selecting a product (either Product A, Product B, or Product C) and a size.
I want, for each of the other products, to determine which size is closest to the selected product:
I don't know how to solve this. One solution might be to remove all non-numeric characters from the strings and add the two values on each side of the "x" and then select the size with the lowest absolute difference from the sum of the selected size.
But I guess it would be easier to do a mapping and use a VLOOKUP to choose the first found size in a given column.
However, the problem is that I do not only have 3 products with a few different sizes, but rather 15 different products with 10 different sizes, so I don't know how to do a mapping in a clever way.
1) Creating a lookup table with the values extracted for each product,
Source sheet:
Code:
Sub lookup()
Dim i As Long, j As Long, prod As Integer, str As String
prod = InputBox("Enter Number of Products")
Sheets.Add.Name = "LookupSheet"
j = 1
For i = 1 To prod
Columns(i).Copy Sheets("LookupSheet").Cells(1, j)
j = j + 2
Next i
For j = 1 To prod * 2 Step 2
For i = 2 To Sheets("LookupSheet").Cells(Rows.Count, j).End(xlUp).Row
str = Replace(Replace(Sheets("LookupSheet").Cells(i, j), " ", ""), "cm", "")
Sheets("LookupSheet").Cells(i, j + 1) = Left(str, InStr(str, "x") - 1) _
* Mid(str, InStr(str, "x") + 1, 999)
Next i
Next j
End Sub
This simple code creates a lookup sheet with the corresponding values. The code ignores any spaces present between the texts.
LookupSheet:
Since you have 15 different products, run this macro to extract the lookup data. This should be a one time activity unless you have additional products.
2) Assuming you enter the product and dimensions to F5 and F6, i would suggest you to data validation with dropdowns to select from the list,
3) Using a worksheet_change event, detect for changes in F5 and F6,
Code:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim str As String, result As Integer, i As Long
'F5 and F6 contains Product and Size repectively
If (Target.Address = "$F$5" Or Target.Address = "$F$6") _
And Range("F5") <> "" And Range("F6") <> "" Then
str = Replace(Replace(Range("F6"), " ", ""), "cm", "")
result = Left(str, InStr(str, "x") - 1) * Mid(str, InStr(str, "x") + 1, 999)
j = 8
For i = 1 To Cells(1, Columns.Count).End(xlToLeft).Column
If Cells(1, i) <> Range("F5") Then
Range("E" & j) = Cells(1, i)
j = j + 1
End If
Next i
End If
End Sub
This code automatically populated the rest of the product types in the column E,
4) The variable result would contain the product/area of the value that you provide in F6. The only task pending would be to loop through the lookup sheet to find the nearest match. The Algorithm is below,
Algorithm:
Compare cell F5 with the data in row 1 of lookup sheet (need to loop)
If they are equal, ignore and move to next value. If not, need to loop the immediate next column to find the next match, and populate the result in the corresponding cell in source sheet.
Algorithm for column wise looping is below,
Steps:
diff = cell.value - result
if diff < 0 then multiply diff by -1
loop:
nextdiff = nextcell.value - result (multiply by -1 if negative)
if nextdiff < diff then
diff = nextdiff
end if
end loop:
The cell value with the least difference would be your best match for that particular product type.
Bit lengthier explanation, hope this helps.

Extract any first two letters and 6 digit number from an excel and copy it to another cell

How do I extract only the first two letters and the 6 digit number from one cell to another? ie. Column 1 will have aa111111, bb222222, ccccc, dd12, eeee1
I only want to copy aa111111 and bb222222 in this case.
Thanks,
Alex
Try this short macro:
Sub KopyKat()
Dim N As Long, i As Long, K As Long
Dim s As String
N = Cells(Rows.Count, 1).End(xlUp).Row
K = 1
For i = 1 To N
s = Cells(i, 1).Value
If Len(s) = 8 _
And Mid(s, 1, 1) Like "[a-zA-Z]" _
And Mid(s, 2, 1) Like "[a-zA-Z]" _
And IsNumeric(Mid(s, 3)) Then
Cells(K, 2).Value = s
K = K + 1
End If
Next i
End Sub
If your strings are in A:A then in B1 (and copy down):
=IF(LEN(A1)>7,IF(AND(CODE(LOWER(MID(A1,{1,2},1)))<>CODE(UPPER(MID(A1,{1,2},1))),ISNUMBER(MID(A1,{3;4;5;6;7;8},1)*1)),LEFT(A1,8),""),"")
This is an array formula and must be confirmed with ctrl + shift + enter.
Running evaluate formula shows what happens and how it works :)
Using VBA then this will do:
Sub CopyMe()
Dim x As Variant, i As Long
For Each x In Range([A1], Cells(Rows.Count, 1).End(xlUp)).Value2
If x Like "[a-zA-Z][a-zA-Z]######" Then
i = i + 1
Cells(i, 2) = x
End If
Next
End Sub
Here is another way to do it. The formula loops through your string looking for a 6 digit number, at which point it takes the previous two characters (as long as they exist) and returns the 8 character string. Otherwise it returns an empty string.
=IFERROR(MID(A1,SUMPRODUCT(ROW($A$1:$A$100),--ISNUMBER(VALUE(MID(A1,ROW($A$1:$A$100),6))))-2,8),"")
Loops 100 times, so will work with strings up to a maximum length of 106 characters. To use the formula place your string in column A, and place this formula in cell B1 (for example) and drag down

excel vba accessing worksheets

I have a user that is in need of accessing the raw data in a worksheet. We gather numbers throughout the month based on a estimate. At the end of the month the numbers need to be adjusted to the exact total amount. The user more-or-less randomly adjusts some or all of the items until the estimate entered = the exact amount. In other words, I can't just adjust every item by, say, 2% or $50. The user manually goes thru the list of items and assigns adjustments. My question is: can I send the user to the worksheet to make the adjustments and have the user return to the userform that called the worksheet?
Say a month's end we have:
So values were entered in A1 thru A31There is a SUM() formula 8n A32
To perform the adjustment, enter the actual month value in B32 and run this small macro:
Sub dural()
Dim v1 As Long, v2 As Long, delta As Long
v1 = Range("A32").Value
v2 = Range("B32").Value
If v1 = v2 Then Exit Sub
delta = v2 - v1
If delta > 0 Then
For i = 1 To delta
j = Application.WorksheetFunction.RandBetween(1, 31)
Cells(j, 1).Value = Cells(j, 1).Value + 1
Next i
Else
For i = 1 To -delta
j = Application.WorksheetFunction.RandBetween(1, 31)
Cells(j, 1).Value = Cells(j, 1).Value - 1
Next i
End If
End Sub
Results in:

Resources