I am looping through different process ids to access the data within the json and copy it to my spreadsheet. However, some of the process id contain no data and every time my code gets to these empty arrays I get an error. I have tried different variations of if statements to skip this but still get an error. The empty array is at "expectedRateSetList"
I have tried different variations of if statements to skip this but still get an error. I've tried 'If J is null, if J is nothing, If J is empty" etc but I still can't get it to work. I've also tried "On error go to" but this hasn't worked.
`````````````
For l = 2 To last_row(tb, 2)
Set J = setJSON(url)
Set J = CallByName(J, "expectedRateSetList", VbGet) <---This is the array that is empty
If J Is Null Then GoTo next_log
On Error GoTo next_log
Set J = CallByName(J, "0", VbGet)
Set J = CallByName(J, "expectedRateList", VbGet)
next_log:
Next l
'json array looks like this:
{"processId":X,"expectedRateSetList":[],"warehouseId":"warehouseX"}
J is definitely not an array. J is an object, likely a Dictionary. You can check if a dictionary contains any items by querying its Count property - that removes the need for the line label and GoTo jump, at the cost of increased nesting (but then, the loop body should probably be refactored into its own procedure anyway):
If J.Count > 0 Then
' there are items
End If
Next
Note that CallByName(J, "MemberName", vbGet) can be replaced by late-bound J.MemberName calls - but then again assuming your parsing isn't hand-crafted and you are getting nested dictionaries, that would be J("MemberName"); the property you're actually invoking is the (default) Items property: J.Items("MemberName") is equivalent.
Related
Within a loop I would like to write values to a cell only if a string combination has not already been gone through.
So I am trying to create a dictionary containing an array (the combination of two string variables) and then to check if this combination already exists in the dictionary. My code is the following and I get the “Invalid procedure call or argument” error at the first line. Could you please help me solve this?
…
If Not my_dict.exists(arr) Then
With my_sheet.Cells(x, COL_DOC)
.Value = string1
End With
arr = Array(string1, string2)
my_dict.Add k, arr
k = k + 1
End If
…
I'm working with a spreadsheet that is used for data gathering. I've been asked to create an error checker for when data is pasted into the spreadsheet and overwrites the data validation rules.
In cells X3:AO33, I have a block of formulas. Most of them check for a blank cell, then check for valid entry in another cell. If the result is valid or not needed, it returns a blank. Otherwise, it returns a message. Here's an example:
=IF(OR(AND(D3<>"",OR(F3="",G3="",H3="")),AND(U3<>"",V3="")),CONCATENATE("Required fields are missing in row ",ROW(),"."),"")
Now I need to put something in B2 that looks for messages in the X3:AO33 range. I want it to return the value of the first non-blank cell. If Z5 has the first found error, then B2 should display the text in Z5. Then the user can fix the problem, which makes Z5 turn blank, and if the next error is in AB7, B2 should then display the text in AB7.
I've tried this.
=INDEX(X3:AO33,MATCH(FALSE,ISBLANK(X3:AO33),0))
And this.
=INDEX(X3:AO33,MATCH(TRUE,INDEX((X3:AO33<>0),0),0))
And this.
=INDEX(X3:AO33,MATCH(TRUE,LEN(X3:AO33)>0,0))
And this.
=MATCH("*",X3:AO33,0)
I've tried them all as arrays and not as arrays. And they all bring back the #N/A error.
Any ideas what I'm doing wrong?
I improved my original formula. This will consistently get you the first non-blank going left to right, then down. See sample sheet.
=LEFT(TEXTJOIN("??",TRUE,X3:AO30),FIND("??",TEXTJOIN("??",TRUE,X3:AO30))-1)
Also, you could use a custom function, that gives you the option to go up down or left right.
Function firstNoneBlank(theRange As Range, Optional upDownTrue As Boolean) As Variant
Dim i As Long, j As Long
Set theRange = Intersect(theRange, theRange.Worksheet.UsedRange)
For i = 1 To IIf(upDownTrue, theRange.Rows.Count, theRange.Columns.Count)
For j = 1 To IIf(upDownTrue, theRange.Columns.Count, theRange.Rows.Count)
If theRange.Cells(i, j).Value <> "" Then
firstNoneBlank = theRange.Cells(i, j).Value
Exit Function
End If
Next j
Next i
firstNoneBlank = "#AllBlanks"
End Function
I'm running into a problem with a block of code I'm trying to develop at my job. Essentially, I'm creating a userform in excel where folks will enter data for railcars as they get loaded at a certain location (we'll call these "spot 1, spot 2, spot 3, etc.").
Sometimes they'll have to move that car to a different spot, in which case I want them to be able to keep all the information on the railcar from the first/original entry, and then erase the data from the original spot once that's done.
To accomplish this in a more streamlined fashion, I've established arrays for each of the 5 spots that reference all the cells they're entering data into on the userform:
Dim spot1information(14)
spot1information(0) = UserForm.ProductType1.Value
spot1information(1) = UserForm.ProductID1.Value
spot1information(2) = UserForm.BatchID1.Value
etc....
Dim spot2information(14)
spot2information(0) = UserForm.ProductType2.Value
spot2information(1) = UserForm.ProductID2.Value
spot2information(2) = UserForm.BatchID2.Value
etc....
And so forth for all five spots. I don't know if this makes things more difficult, but note that these array values aren't all of the same type. For instance, index (0) will be a string, but index (10) is a DATETIME and index (12) is defined as Long.
So say that they are moving a car from spot 1 to spot 2. In short, I want the code to do the following:
Replace the values of indices 0 - 6 in spot2information (which is currently empty) with the values of indices 0 - 6 in spot1information (which the user has filled on the userform).
I'm only interested in carrying over indices 0-6 because they contain the pertinent railcar information
Empty every value of spot1information to ""
To accomplish this, I tried the following code and a few variations thereof:
If OriginalSpot.Value = 1 Then
If DestinationSpot.Value = 2 Then
For i = 0 to 6
spot2information(i) = spot1information(i)
Next
For Each i in spot1information
spot1information(i) = ""
Next
End If
End If
However, this keeps coming up with a type mismatch. I figure because the data in the spot2information array is empty, and the data in the spot1information array is not, but I'm not entirely sure of a way around this.
Update: I did what was suggested below and replaced: spot1information(i) = "" with Erase spot1information
The code now essentially works! The values of array "spot2information" are now the former values of "spot1information", with "spot1information" now empty.
The 2D array suggested below also works like a charm. New problem I've been facing is that array values are updating, but the userform isn't. (note: in the future I'll be posting this type of thing as a separate question, my apologies!)
Easier to manage this as a 2D array:
Sub Tester()
Dim spots(1 To 5, 0 To 14), n As Long, i As Long
'fill your spot arrays from the form....
For n = 1 To 5
spots(n, 0) = UserForm.Controls("ProductType" & n).Value
spots(n, 1) = UserForm.Controls("ProductID" & n).Value
spots(n, 2) = UserForm.Controls("BatchID" & n).Value
'etc etc
Next n
'swap a spot with another
Debug.Print spots(2, 1), spots(3, 1)
SwapSpots spots:=spots, fromSpot:=2, toSpot:=3
Debug.Print spots(2, 1), spots(3, 1)
End Sub
Sub SwapSpots(spots, fromSpot As Long, toSpot As Long)
Dim n As Long
For n = 0 To 6
spots(toSpot, n) = spots(fromSpot, n)
spots(fromSpot, n) = Empty 'empty the source slot value
Next n
End Sub
Assuming the DataType of the arrays is the same by Index i.e. index(0) is string for all spots, Index(2) is long for all spots, and so on.
If that is the case then this part should not produce any error:
For i = 0 to 6
spot2information(i) = spot1information(i)
Next
The error should be happening in this part more precisely in the line marked with #
For Each i in spot1information
spot1information(i) = "" '#
Next
and the reason for the error it seems to be that trying to assign a string value "" to a numeric type, given the "mismatch" error.
Using For Each i in spot1information indicates that you want to "Initiate" or Erase the entire array, therefore I suggest to use this line instead of the For…Next method.
Erase spot1information
In regards this:
But I've now run into a new problem, where the values on the userform haven't updated to reflect the new values stored in the array. Do I need to somehow "refresh" the userform?
You just updated the arrays, then you need to run the procedures used to update the values of the objects affected by both arrays in the UserForm.
I am working to get my code to loop through arrays of JSON strings (of same format) until it reaches the end of the arrays (i.e., no strings left). I need the code to recognize it has reached the end by identifying that a certain identifier (present in every set) does not have additional information in the next array. So I believe I am looking for "while" syntax that says "while this identifier has content" proceed parsing the JSON according to the below code. My existing code works for array of strings for which I know the length - unfortunately the lengths are variable therefore I need flexible syntax to adjust with the lengths (i.e., "For 0 to n" doesn't work every time).
The JSON code I am parsing is in this format:
{"id":1,"prices":[{"name":"expressTaxi","cost":{"base":"USD4.50","fareType":
"time_plus_distance","cancelFee":"USD10.00","minimumAmt":"USD8.00","perMinute":"USD1.50",
"perDistanceUnit":"USD3.00"}}]
''note that this could have multiple arrays embedded. That is, from the "name" key to
''the "perDistanceUnit" key would all repeat, with different value pairs.
''The number of "name" to "perDistanceUnit" arrays is unknown.
Here the identifier structure I'd like to augment with some type of while loop (the "i" is the index number depending on the # of loop in the yet to be implemented "while" loop).
Json("prices")(i)("name")
So ideally looking for something like:
"While Json("prices")(i)("name") has information" then proceed on....
Please note again, everything works when I know the length -- just looking for a small syntax update, thank you! UPDATE: full code below:
Option Explicit
Sub getJSON()
sheetCount = 1
i = 1
urlArray = Array("URL1", “URL2”, “URL3”)
Dim MyRequest As Object: Set MyRequest = CreateObject("WinHttp.WinHttpRequest.5.1")
Dim MyUrls: MyUrls = urlArray
Dim k As Long
Dim Json As Object
For k = LBound(MyUrls) To UBound(MyUrls)
With MyRequest
.Open "GET", MyUrls(k)
.Send
Set Json = JsonConverter.ParseJson(.ResponseText)
''[where I’d like some type of While statement checking into the below line for content]
Sheets("Sheet" & sheetCount).Cells(i, 1) = Json("prices")(i)("name")
Sheets("Sheet" & sheetCount).Cells(i, 2) = Json("prices")(i)("cost")("base")
i = i + 1
End With
sheetCount = sheetCount + 1
Next
End Sub
I'm not that familiar with the library you're using, bit it seems like it converts objects (items enclosed in { }) to dictionary objects, and array (things enclosed in [ ]) to Collections.
Depending on the structure of the parsed JSON, these objects may be nested: ie. one element in a dictionary may be a Collection(array).
Luckily for you both, of these object types have a Count property you can use to iterate over them (and the dictionary type also has a "keys" collection).
So to loop over each "price":
Dim i As Long, p As Object
For i = 1 To Json("prices").Count
Set p = Json("prices")(i)
Debug.Print p("name"), p("cost")("base"), p("cost")("fareType")
Next i
Hi I'm working on a macro in VBA for excel. I have a nested for loop in my code as seen below. The second loop does not run; even a MsgBox() command within the second loop doesn't result in any action and the program just seems to skip over the nested loop with no reported errors.
In plain English this nested loop should:
1) Take the string from the i entry in the array categories_string (first for loop).
2) iterate through the 300+ rows in column "AE" in the excel file (second for loop, "length" is the length of the column of data in "AE")
3) look for string matches and add 1 to the corresponding entry in the categories_value array which is populated with variables set to 0 (the if statement).
For i = LBound(categories_string) To UBound(categories_string)
For p = 1 To p = length
If Worksheets("sheet1").Cells(p + 2, "AE").Value = categories_string(i) Then
categories_value(i) = categories_value(i) + 1
End If
Next
Next
Change
For p = 1 To p = length
to
For p = 1 To length
Should fix you right up.
You may want to consider Scott Cranner's comment as well, especially if your categories_string is large and length is large. Or, just do it for the practice