Getting values from a multi column listbox VBA - vba

I am in need of help, I am trying to get all three columns of my multi column list box in a for loop, it should be pretty simple but I cannot figure it out,
I have googled for hours and to be honest haven't gotten anywhere as everyone wants it to be able to select and then loop through where as i just want to loop through all of them and take them to separate strings,
Hope this makes sense,
Thank you,

You can cycle through entries in the list by using the script below and fill a new array which can be pasted to an assigned range on the sheet of the same size as the array
dim arrayctr as integer, i as integer, myarray() as variant
With mylistbox
'below sizes array to size of list in listbox.
'use arrctr to populate selected items to array without blank entries in between.
redim myarray(1 to .listcount, 1 to 1) as variant
'.listcount gives total entries, but list starts from 0 so use i-1 to get values
For i = 1 to .listcount
if .selected(i-1) = true then myarray(arrayctr) = .list(i-1): _
arrctr = arrctr + 1
Next i
End with
you can use For next loop through entries and use Exit For when the value of the array = "" so it handles only entries with data in and avoids pointless calculations.
I have had similar troubles with finding online answers to some questions such as this, I hope it helps!

Related

Determine if an integer is a member of a list of integers

I need to determine if a particular integer does not exists in a datagridview column. I assume I should create an array of the integers from the dgv column, and then compare if the integer exists in the array. However, there is perhaps an easier or simpler way.
I have looked at many articles but none of them resolve my task. Some of the Stack Overflow articles show similar solutions but I can't quite determine what to do.
For a = 0 To Dgv1.RowCount - 1
If Not Dgv1(1, a).Value = Dgv0(1, m).Value Then
Dgv0(1, Dgv0.RowCount - 1).Value = Dgv0(1, m).Value
End If
Next
I hope to compare an integer with a column of integers in a datagridview and if it is present do nothing but if is not present add it to the datagrid view
Are you using wpf? If yes, create a model.
provide a checking mechanism at the setter, use observablecollection or list then bind it to the datagirdview
Get the row and column of the datagridview
then compare (means condtional statement) to the variable you wanna check
and of course it should be inside of loop, loop count is equal to the count of rows you have in the datagridview.
Here's an example code:
Dim column As String = "YourColumnNameHere"
' Assuming 2 is the number you wanna compare
Dim value As Integer = 2
For row As integer = 0 to dataGridView.RowCount - 1
If dataGridView.Rows(row).Cells(column).Value = value Then
' Do something here
Else
' Do something here
End If
Next

Using variable sheetname in VBA

I'm a novice at VBA (just starting to learn). In my userform I have a combobox with values from 1 to 12(not string) representing the months. I want the user to pick a month and based on that, the multiple listboxes and labels I have placed should get filled by the relevant values in one of the 12 sheets representing each month. as I am a novice I have a lot of problems here but for starters the following lines do not seem to work on userform_initiate()
For j = 0 To 1
arr_trh(0, j) = Sheets("Sheet6").Cells(4, j + 1)
Next j
I can get it to work for a single sheet by using
arr_trh(0, j) = Sheet6.Cells(4, j + 1)
However, what I'm trying to do later on is to create a string and somehow concatenate "Sheet" and combobox value to pass on to Sheets() function.
Any help would be appreciated
Thanks
Rather than referring to the Sheet object like:
v = Sheet1.Range("A1")
use:
v = Sheets(1).Range("A1")
which you can index like:
v = Sheets(i).Range("A1")
where i is a variable.
I guess, my this answer will help you to figure out how to refer to sheets. Also, it tells about caveats of Index property.

Comparing two lists in excel and extracting values missing from 2nd list - cannot be duplicated (also over two sheets)

Im working on a project report for work and I'm trying to find a way to compare two lists of project codes i.e "123456" and see whether the 2nd list is missing any new values that would've been entered into the first list. The lists are thousands of records long and so far people have been doing it manually (it hurts me knowing this) so I'm trying to make it automatic.
What I have tried is using an Array with a Index(Match(CountIF))) formula but I just cant seem to get it working.
My problem is that when I get the array to fill with what i want I then can't get it to not duplicate values (I need it to check the masterlist so it doesnt output something more than once into the output list).
I've also tried to give it a go with other formulas - but the lists can be thousands of records long so I cant do a cell for cell match as the list would be huge (that or my excel knowledge isnt good enough to know the easy solution).
Any help would be hugely appreciated.
Array might not be the best solution
I've checked quite a few other solutions but they don't quite deal with my issue and I don't have the skill to adapt them.
Here is one approach using VBA and arrays which is quicker than doing via the sheet. It checks each item in H to see it is present in J (and not the other way round). I assume that's what you want.
Sub x()
Dim v1, v2, v3(), i As Long, j As Long
v1 = Range("H2", Range("H" & Rows.Count).End(xlUp)).Value
v2 = Range("J2", Range("J" & Rows.Count).End(xlUp)).Value
ReDim v3(1 To UBound(v1, 1))
For i = LBound(v1) To UBound(v1)
If IsError(Application.Match(v1(i, 1), v2, 0)) Then
j = j + 1
v3(j) = v1(i, 1)
End If
Next i
Range("K2").Resize(j) = Application.Transpose(v3)
End Sub
Using an input box
Sub x()
Dim v1, v2, v3(), i As Long, j As Long
v1 = Application.InputBox("First list", Type:=8)
v2 = Application.InputBox("Second list", Type:=8)
ReDim v3(1 To UBound(v1, 1))
For i = LBound(v1) To UBound(v1)
If IsError(Application.Match(v1(i, 1), v2, 0)) Then
j = j + 1
v3(j) = v1(i, 1)
End If
Next i
Range("K2").Resize(j) = Application.Transpose(v3)
End Sub
A formula solution.
Note that I turned the first two ranges into Tables and changed the names. The formula is using structured references. This enables the formula to auto update if you add rows in the future.
=IFERROR(INDEX(ProjList1[#Data],AGGREGATE(15,6,1/ISNA(MATCH(ProjList1[#Data],ProjList2[#Data],0))*ROW(ProjList1[#Data]),ROWS($1:1))-ROW(ProjList1[#Headers])),"")
How does it work? Briefly:
MATCH generates an array of #NA! errors or a number.
ISNA turns that into an array of TRUE/FALSE where TRUE indicates an entry in table 1 that is NOT in table 2
Multiplying that array by the array of project list rows returns an array of error message vs row number
AGGREGATE small function ignores the error returns to give an ascending list of row numbers
INDEX then returns the appropriate entry from Table 1
ROW(ProjList1[#Headers]) is a correction so that the table may be located anyplace on the worksheet, and still return the correct row.
Not sure if you're trying to set this up so it will autoupdate in future, but as a stopgap:
Countif column next to list 1 that checks whether they appear in list 2...
... Feeding into a pivot that only shows those where the countif value is 0, in the "row" field to remove duplication?

How to use variables in regular MS excel expressions

My research shows that I need to use Visual Basic. I am a programmer/developer, but have never used VB so if anyone could dumb it down it would be appreciated.
Here's my working excel function:
=IF(MATCH(1,E1:DP1,0),D1,FALSE)
I want to loop a few of those numbers such that:
=IF(MATCH(141,E1:DP378,0),D378,FALSE)
THEN take my answers (which will be strings, because column D are all strings, the rest of the excel file are numbers)
=CONCAT
end goal: have 141 String arrays populated based on the data in my table.
I went ahead and made my first attempt at VBA like this:
Sub myFunc()
'Initialize Variables
Dim strings As Range, nums As Integer, answer() As Variant, listAnswers() As Variant
'set variables
strings = ("C1:C378")
nums = 141
i = 0
j = 0
ReDim Preserve answer(i)
ReDim Preserve listAnswers(j)
'answer() = {""}
'for each in nums
For counter = 0 To nums
ReDim Preserve listAnswers(0 To j)
'set each list of answers
listAnswers(i) = Join(answer(), "insertJSONcode")
j = j + 1
'for each in Stings
For Each cell In strings
If cell <> "" Then
ReDim Preserve answer(0 To i)
answer(i) = 'essentially this: (MATCH(2,E1:DP1,0),D1,FALSE)
i = i + 1
end If
next cell 'end embedded forEach
Next LCounter 'end for loop
'is this possible? or wrong syntax?
Range("A:A").Value = listAnswers() ' should print 141 arrays from A1 to A141
End Sub
EDIT:
Important note I do NOT need to call the sheet by Name. I've successfully written integer values to by excel sheet in column A without doing so.
Also, the VBA I wrote I was never intended to work, I know it's broken at least where answer(i) is supposed to write to something. I'm only putting that code there to show I was able to at least able to get into spitting distance of the proper logic and prove I've put some serious effort into solving the problem and give a rough starting point.
Here's an image of the excel format. Column C goes down to 378 and the numbers listed from E through DP are populated by a database. It consists of blank cells and numbers between 1 and 141.
Looking back at my if statement:
=IF(MATCH(2,E2:DP2,0),D2,FALSE)
If I were to type that exactly into cell B2 it would output the correct answer "text2". which is neat and all, but I need every instance of text 2 written out, then CONCAT those results. Easy so far, I could drag that down all the way through column B and have all of my "text" strings in one column, CONCAT that column and there's the answer. However I don't just need #2, I need each number between 1 and 141. Plus I want to avoid writing 141 columns with a CONCAT on top of each one.

Fill Series, a lot of Series's?

In Excel I've got sequential box numbers in column B, and each box has a couple dozen files that need sequential-by-box place numbers in column C. The way I usually do this is to Fill Series down a selection (selected by hand) of all the cells for that box in Column C, which is fine if you've got a few boxes to do, but now I have several hundred.
[I've got a 394x290 example screenshot I was going to include to show what I mean, but since this is my first post I don't have enough rep, sorry -- link to it on g+ here.]
I thought I could put some VBA code into a macro to select the contiguous cells with the same box number, offset one column right [Offset (0, 1), yeah?], fill series those cells from 1, and go on to the next box. But I haven't had any luck finding anything similar that's been done, nor have I been able to get anything I've looked up to work for this. (Not surprising since I rarely try VBA, hopefully my question's not too noobish for this site.)
From what I can tell, you want the Plc column to fill up series starting from 1 for the same Box Num.
There may exist a fast and quick way but simple method is to go through the rows. Try below:
Sub FillUpPlc()
Dim oRng As Range, n As Long ' n used for series filling
Application.ScreenUpdating = False
n = 1
Set oRng = Range("B2")
Do Until IsEmpty(oRng)
' Increment n if it's same as cell above, otherwise reset to 1
If oRng.Value = oRng.Offset(-1, 0).Value Then
n = n + 1
Else
n = 1
End If
oRng.Offset(0, 1).Value = n ' Store n to next column
Set oRng = oRng.Offset(1, 0) ' Move to next row
Loop
Set oRng = Nothing
Application.ScreenUpdating = True
End Sub
No need to break out the VBA. This can be done with a formula. Starting in C2 and copied down
=IF(B2<>B1,1,C1+1)
Much, much faster than VBA looping through thousands of rows.