How to transpose a 2D list with repeating objects - transpose

I have been trying to write some VBA in Excel to transpose a 2D list, based on searching for the first character "{".
Before:
After:
My code:
With Sheets("Results").Range(Cell1:="A1", Cell2:="A39")
Set a = .Find("{", After:=Range("A" & lRow))
Set b = a
c = a.Address
Do While Not .FindNext(b) Is Nothing And a.Address <> .FindNext(b).Address
c = c & "," & .FindNext(b).Address
rangeToMoveCell1 = a.Address
rangeToMoveCell2 = .FindNext(b).Address
MsgBox ("rangeToMoveCell1: " & rangeToMoveCell1 & vbNewLine & "rangeToMoveCell2: " & rangeToMoveCell2)
Sheets("Results").Range(Cell1:=rangeToMoveCell1, Cell2:=rangeToMoveCell2).Copy
Sheets("Results").Range(Cell1:=rangeToMoveCell1, Cell2:=rangeToMoveCell2).Offset(-3, 1).PasteSpecial Transpose:=True
Sheets("Results").Range(Cell1:=rangeToMoveCell1, Cell2:=rangeToMoveCell2).Clear
Set b = .FindNext(b)
Loop
End With

I've come up with this and it works, except it does not process the last find:
With Sheets("Results").Range(Cell1:="A1", Cell2:="A" & lRow)
Set a = .Find("{", After:=Range("B" & lRow))
Set b = a
c = a.Offset(3).Address
Do While Not .FindNext(b) Is Nothing And a.Address <> .FindNext(b).Address
Set nextFind = .FindNext(b)
Set d = nextFind
'MsgBox ("d: " & d)
e = nextFind.Offset(-1, 1).Address
Sheets("Results").Range(Cell1:=c, Cell2:=e).Copy
Sheets("Results").Range(Cell1:=c, Cell2:=e).Offset(-3, 2).PasteSpecial Transpose:=True
Sheets("Results").Range(Cell1:=c, Cell2:=e).EntireRow.Delete
Sheets("Results").Range(c).EntireRow.Insert
Sheets("Results").Range(c).EntireRow.Insert
c = nextFind.Offset(3).Address
Set b = .FindNext(b)
Loop
End With

Related

How to populate listbox1 (without userform) with different colums from different sheets

My listbox is populated with 1 column of a specific sheet.
How can I get a second and third column in my listbox?
I mean... Column B from sheet1, column C from sheet2 and column B from sheet3, each with a second column from the sheets.
In this case I have a textbox where you can type your search.
This already works for me for just 1 specific column of 1 sheet:
Private Sub textbox1_change() 'zoekt via zoekterm boxpositie de mogelijke boxposities op
Dim i As Long
Dim x As Integer
Dim Sheet1 As Worksheet
TextBox1 = Format(StrConv(TextBox1, vbUpperCase))
Set Sheet1 = Worksheets("Cytolab")
a = TextBox1.TextLength
ListBox1.Clear
ListBox1.Height = 101
ListBox1.Top = 290
ListBox1.Width = 512
For i = 5 To Sheet1.Range("B238").End(xlUp).row
For x = 1 To Len(Sheet1.Cells(i, 2))
If UCase(Mid(Sheet1.Cells(i, 2), x, a)) = TextBox1 And TextBox1 <> "" Then
ListBox1.AddItem CStr(Sheet1.Cells(i, 2)) 'CStr() toegevoegd
ListBox1.List(ListBox1.ListCount - 1, 1) = "" & Sheet1.Cells(i, 3) & " · " & Sheet1.Cells(i, 7) & " · " & Sheet1.Cells(i, 5) & " · " & Sheet1.Cells(i, 4)
ListBox1.List(ListBox1.ListCount - 1, 2) = "" & Sheet1.Cells(i, 9)
End If
Next x
Next i
End Sub
Thank you.

Why does "array[index]" return "nil"?

this problem seems very simple but I cannot find a solution for it, actually I don't even know what is wrong!!!
So basically I have this Lua code:
io.write("\nPlease provide the message to be decyphered: ")
message = io.read()
seq = #message
ffib = {}
a = 0
b = 1
c = a + b
fib = 0
while c < (seq - 10) do
fib = fib + 1
ffib[fib] = c
a = b
b = c
c = a + b
end
decyphered = ""
for i = 1,seq do
decyphered = table.concat{decyphered, message:sub(ffib[i],ffib[i])}
end
io.write("\nDecyphered message: ", decyphered, "\n\n")
and trying to access ffib[fib] returns nil. So trying to message:sub(ffib[i]... later throws an error.
When I try accessing ffib's values manually, ffib[1] for example, it works alright, it's only when trying to access it with an iterator that it screws up.
Somewhere else in my code I have this:
io.write("\nPlease provide the message to be cyphered: ")
message = io.read()
cyphered = ""
seq = #message
ffib = {}
a = 0
b = 1
c = a + b
for fib = 1,seq do
ffib[fib] = c
a = b
b = c
c = a + b
end
which is basically the same thing but instead of using a while loop, it uses a for loop, and it works just fine!
Please help me solve this I am going insane.
Alright, I figured it out!
io.write("\nPlease provide the message to be decyphered: ")
message = io.read()
seq = #message
ffib = {}
a = 0
b = 1
c = a + b
fib = 0
while c < (seq - 10) do
fib = fib + 1
ffib[fib] = c
a = b
b = c
c = a + b
end
decyphered = ""
for i = 1,seq do <--------------
decyphered = table.concat{decyphered, message:sub(ffib[i],ffib[i])}
end
io.write("\nDecyphered message: ", decyphered, "\n\n")
I was using the wrong variable in the for loop, so it was looping through the entire message length instead of the fibonacci array length, the "nil" values were indexes out of bounds!
To correct this, I simply changed seq for #ffib in that For Loop, marked by an arrow.
Thanks everyone who tried to help me anyway!
this part doesn't make much sense I think
while c < (seq - 10) do
Why the minus 10? ffib will have less entries than seq while in the loop after that you expect a value in ffib from 1 to seq
And even if you change it to
while c < seq do
Then there still won't be enough for messages larger than length 2.
If anything, you might want to do
while c < (seq + 10) do
But even there you will run into an issue when the message is a certain length.
I'm also not familiar with that algorithm, but it looks pretty weird to me and I wonder what it actually establishes

How can I generate an array of numbers between multiple ranges defined in separate cells in Sheet?

A1: 1 | B1: 4
A2: 3 | B2: 6
How can I get {1, 2, 3, 3, 4, 4, 5, 6} out of this?
– – – – – –
I know this way:
=ArrayFormula({ROW(INDIRECT(A1&":"&B1)); ROW(INDIRECT(A2&":"&B2))})
That does the job perfectly but what if I don't know, how many ranges there will be? I want to generate an array of all the numbers between values specified in cells from A1:B1 all the way to A:B.
Thank you in advance!
Here is a relatively simple formula to generate the array you're talking about based on an infinite number of ranges in columns A and B.
=ARRAYFORMULA(QUERY(SPLIT(FLATTEN(SEQUENCE(1,MAX(B1:B10-A1:A10)+1,0)+A1:A10&"|"&B1:B10),"|",0,0),"Select Col1 where Col1<=Col2 order by Col1",0))
You can see it demonstrated in the tab called Demo 2 on this sheet.
In Excel 365 with your data in columns A and B, pick a cell and enter:
="{" & TEXTJOIN(",",TRUE,SEQUENCE(,MAX(A:B),MIN(A:B))) & "}"
EDIT#1:
Try this VBA macro:
Sub MakeArray()
Dim I As Long, N As Long, J, k
Dim strng As String
Dim arr As Variant
N = Cells(Rows.Count, "A").End(xlUp).Row
For I = 1 To N
For J = Cells(I, 1) To Cells(I, 2)
strng = strng & "," & J
Next J
Next I
strng = Mid(strng, 2)
strng = "{" & Join(fSort(Split(strng, ",")), ",") & "}"
MsgBox strng
End Sub
Public Function fSort(ByVal arry)
Dim I As Long, J As Long, Low As Long
Dim Hi As Long, Temp As Variant
Low = LBound(arry)
Hi = UBound(arry)
J = (Hi - Low + 1) \ 2
Do While J > 0
For I = Low To Hi - J
If arry(I) > arry(I + J) Then
Temp = arry(I)
arry(I) = arry(I + J)
arry(I + J) = Temp
End If
Next I
For I = Hi - J To Low Step -1
If arry(I) > arry(I + J) Then
Temp = arry(I)
arry(I) = arry(I + J)
arry(I + J) = Temp
End If
Next I
J = J \ 2
Loop
fSort = arry
End Function
The macro:
creates a comma-separated string from each A/B pair
sorts the string
outputs the string

vbscript using InStr to find info that varies within a URL

I have a project where the user pulls up a specific URL where the values for Dept, Queue, and Day change by what hyperlink they choose. For example, they would click on a hyperlink and the URL would be something like:
http://www.myworkplace.com/UserPlatform/User/Process.aspx?Dept=DeptOne&Queue=18&Day=0
The next hyperlink could be:
http://www.myworkplace.com/UserPlatform/User/Process.aspx?Dept=DeptFive&Queue=13&Day=9.
I would like to use InStr to find Dept, Queue, and Day within the URL, then set their values to variables, such as UDept, UQueue, and UDay. Depending upon these values, the user can then copy a specific ID number that can only be found on the URL with these values. The end result would be a search for the URL:
http://www.myworkplace.com/UserPlatform/User/Process.aspx?Dept=UDept&Queue=UQueue&Day=UDay
Here's my code so far:
Option Explicit
Dim objIE, objShell, objShellWindows
Dim strIDNum, strURL, strWindow, strURLFound, WShell, i
strURL = "http://www.myworkplace.com/UserPlatform/User/Process.aspx?Dept=DeptOne&Queue=18&Day=0"
strWindow = "Workflow Process"
Set objIE = CreateObject("InternetExplorer.Application")
Set objShell = CreateObject("Shell.Application")
Set objShellWindows = objShell.Windows
Set WShell = CreateObject("WScript.Shell")
strURLFound = False
'To fix item not found error
For Each objIE in objShellWindows
Next
For i = 0 to objShellWindows.Count - 1
Set objIE = objShellWindows.Item(i)
On Error Resume Next
If InStr(Ucase(objShellWindows.Item(i).LocationURL), Ucase(strURL)) Then
If InStr(Ucase(objShellWindows.Item(i).FullName), "IEXPLORE.EXE") Then
If Err.Number = 0 Then
If InStr(objShellWindows.Item(i).document.title, (strWindow)) Then
strURLFound = True
Exit For
End If
End If
End If
End If
Next
WShell.AppActivate strWindow
WScript.Sleep 300
strIDNum = objIE.document.getElementByID("ID_PlaceHolder").value
Thank you in advance to anyone who can help me with this.
Have you considered using a regular expression?
dim re, s
dim matches
s = "http://www.myworkplace.com/UserPlatform/User/Process.aspx?Dept=DeptFive&Queue=13&Day=9"
Set re = new RegExp
re.Pattern = ".*?Dept=(\w+)&Queue=(\d+)&Day=(\d+)$"
Set matches = re.Execute(s)
Dim uDept, uQueue, uDay
uDept = matches(0).submatches(0)
uQueue = matches(0).submatches(1)
uDay = matches(0).submatches(2)
Msgbox join(array("uDept = " & uDept, "uQueue = " & uQueue , "uDay = " & uDay), vbNewLine)
' Output:
' uDept = DeptFive
' uQueue = 13
' uDay = 9
To replace you can also use a Regular Expression:
Set re = new RegExp
s = "http://www.myworkplace.com/UserPlatform/User/Process.aspx?Dept=DeptFive&Queue=13&Day=9"
newDept = "DeptFourtyTwo"
newQueue = 404
newDay = 12
re.Pattern = "(Dept=)\w+"
newUrl = re.Replace(s, "$1" & newDept)
re.Pattern = "(Queue=)\d+"
newUrl = re.Replace(newUrl, "$1" & newQueue)
re.Pattern = "(Day=)\d+"
newUrl = re.Replace(newUrl, "$1" & newDay)
msgbox newUrl
' output:
' http://www.myworkplace.com/UserPlatform/User/Process.aspx?Dept=DeptFourtyTwo&Queue=404&Day=12
' Alternatively you can replace everything at once if the order and presence of
' parameters is guaranteed:
re.Pattern = "(Dept=)\w+(&Queue=)\d+(&Day=)\d+"
MsgBox re.Replace(s, "$1DeptFourtyTwo$2404$312")
This only using Instr and Mid Function's
s="http://www.myworkplace.com/UserPlatform/User/Process.aspx?Dept=DeptFive&Queue=13&Day=9"
a = InStr(s, "?") 'We get the value until ?
d1 = Mid(s, a)
c1 = InStr(d1, "=")
c2 = InStr(d1, "&")
d2 = Mid(d1, c2 + 1)
d3 = Mid(d1, c1 + 1, (c2 - c1) - 1) 'value of Dept is d3
c3 = InStr(d2, "=")
c4 = InStr(d2, "&")
d5 = Mid(d2, c4 + 1)
d4 = Mid(d2, c3 + 1, (c4 - c3) - 1) 'value of Queue is d4
c6 = InStr(d5, "=")
d6 = Mid(d5, c6 + 1) ' Value of Day is d6
Hope this helps

How do you reference a table with a key value that is numeric in Lua?

The output for the below script is:
AD[1] = [variable not found]
AD['2'] = bar
How can I modify the function getfield to return a value for v for both cases?
function getfield (f)
local v = _G
for w in string.gfind(f, "[%w_]+") do
v = v[w]
end
return v
end
AD = {[1] = 'foo', ['2'] = 'bar'}
data = {"AD[1]","AD['2']"}
for i,line in ipairs(data) do
s = getfield(line)
if s then
print(line .. " = " .. s)
else
print(line .. " = [variable not found]")
end
end
UPDATE:
I'm 90% sure, this is going to work for me:
function getfield (f)
local v = _G
for w in string.gfind(f, "['%w_]+") do
if (string.find(w,"['%a_]")==nil) then
w = loadstring('return '..w)()
else
w = string.gsub(w, "'", "")
end
v=v[w]
end
return v
end
This happens to work
function getfield (f)
local v = _G
for w in string.gfind(f, "['%w_]+") do
local x = loadstring('return '..w)()
print(w,x)
v = v[x] or v[w]
end
return v
end
AD = {[1] = 'foo', ['2'] = 'bar'}
data = {"AD[1]","AD['2']"}
for i,line in ipairs(data) do
s = getfield(line)
if s then
print(line .. " = " .. s)
else
print(line .. " = [variable not found]")
end
end
but it's pretty fragile.
Note that I added ' to the pattern.
The difficulty is that sometimes w is a string representing a name (key), and sometimes it's a string representing a number. In the second case it needs to be converted from string to number. But you need the context or some syntax to decide.
Here's the kind of fragility I mean:
> data = {"math[pi]","AD['2']"}
>
> for i,line in ipairs(data) do
>> s = getfield(line)
>> if s then
>> print(line .. " = " .. s)
>> else
>> print(line .. " = [variable not found]")
>> end
>> end
math table: 0x10ee05100
pi nil
math[pi] = 3.1415926535898
AD table: 0x10ee19ee0
'2' 2
AD['2'] = bar
> pi = 3
> math[3] = 42
> data = {"math[pi]","AD['2']"}>
> for i,line in ipairs(data) do
>> s = getfield(line)
>> if s then
>> print(line .. " = " .. s)
>> else
>> print(line .. " = [variable not found]")
>> end
>> end
math table: 0x10ee05100
pi 3
math[pi] = 42
AD table: 0x10ee19ee0
'2' 2
AD['2'] = bar
math[pi] is unchanged, but getfield interprets pi in the global context and gets 3 so the wrong field of math is returned.
You'll get the strings '1' and "'2'". You have to evaluate it to turn it into whatever object it is:
v = v[loadstring('return ' .. w)()]
Don't do this if the string came from an untrusted source though (like a user input or something) because they could execute arbitrary code.

Resources