I have a matrix (5x5) with values in them for example:
Matrix (1,1) Value: 'a'
Matrix (1, 2) Value: 'b'
Matrix (2, 1) Value: 'c'
how would I be able to find the letter 'a' in that matrix and have it output the coordinates?
ie
user inputs 'b'
[searches for 'b' in table]
output (1,2)
thanks in advance
It's as simple as:
For i As Integer = 0 To LengthOfMatrix - 1
For y As Integer = 0 To HeightOfMatrix - 1
If Matrix(i, y) = "a" Then Console.Write(i & " " & y & vbCrLf)
Next
Next
Asuming that you declared Matrix as:
Dim Matrix As Char(,) = {{"a", "b", "c", "d", "e"}, {"a", "b", "c", "d", "e"}, {"a", "b", "c", "d", "e"}, {"a", "b", "c", "d", "e"}, {"a", "b", "c", "d", "e"}}
And LengthOfMatrix And HeightOfMatrix should be the dimentions of your matrix. They could be switched to something more dynamic like:
For i As Integer = 0 To Matrix.GetLength(0) - 1 'Get's the length of the first dimension
For y As Integer = 0 To Matrix.GetLength(1) - 1 'Get's the length of the second dimension
If Matrix(i, y) = "a" Then Console.Write(i & " " & y & vbCrLf)
Next
Next
In a short description, all that this loop does is it goes through all of the elements of the matrix and outputs the coordinates of every element that matches a certain criteria (In this case - equals to 'a').
Note: In most programming languages array's indexes begin from 0, so the first element in your matrix will be at coords (0,0).
Related
Say I have the following Dataframe.
df = pd.DataFrame([["a", "b", "c"], ["d", "e", "f"],["g", "h", "i"]])
How do I get the column index of "c" in row 0?
I know there are ways to get the column index if there are column labels, but I can't find ways to return the column index just based on the cell value, if searching a particular row.
Like this:
df[df[df.eq("c").any(1)].T.eq("c").any(1)].index[0]
2
Here's one way:
You can create a extra dataframe that check each cell value in your original dataframe to locate the string inside each cell. Here you would like to find c which can be mapped as follow:
check_df = df.applymap(lambda in_each_cell_value: str(in_each_cell_value).find("c") >= 0)
The check_df returns the boolean values and locates the string in the cell.
From the above 'check_df' you can extract and keep the column where the cell was found:
[column for column, count in check_df.sum().to_dict().items()
if count > 0]
Complete code:
df = pd.DataFrame([["a", "b", "c"], ["d", "e", "f"],["g", "h", "i"]])
check_df = df.applymap(lambda in_each_cell_value: str(in_each_cell_value).find("c") >= 0)
ind = [column for column, count in check_df.sum().to_dict().items()
if count > 0]
Outputs:
ind[0]
2
I have the following binary string (actually a bit array)
"1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0"
which I want to convert to a byte array.
I need this for an embedded report code functions which only accepts a byte array. I've converted this function from powershell.
I found this but it's C#
string source = "1,1,1,0,0";
byte[] result = source
.Split(',')
.Select(item => byte.Parse(item))
.ToArray();
This does not work in report builder ('Select' is not a member of 'System.Array'.)
Dim source As String = "1,1,1,0,0"
Dim result As Byte() = source.Split(","c).[Select](Function(item) Byte.Parse(item)).ToArray()
If I add System.Linq as suggested I'm still getting an error:
'Select' is not a member of 'Linq'.
Dim source As String() = "1,1,1,0,0".Split(","c)
Dim result As Byte() = System.Linq.Select(Function(source) Byte.Parse(source)).ToArray()
After looking at the function more closely I realized that the input can be any array so I modified the type of the array to string and updated my input accordingly. Tank you guys for trying to help.
Function
Function GetSQLProductKey(ByVal astrBinaryKey As String(), ByVal intVersion As Integer) As String
Dim achrKeyChars As Char() = {"B", "C", "D", "F", "G", "H", "J", "K", "M", "P", "Q", "R", "T", "V", "W", "X", "Y", "2", "3", "4", "6", "7", "8", "9"}
Dim strSQLProductKey As String
Dim iastrBinaryKey As Long
Dim iachrKeyChars As Long
Dim iastrBinaryKeyOuterLoop As Long
Dim iastrBinaryKeyInnerLoop As Long
Try
If (intVersion >= 11) Then
iastrBinaryKey = 0
Else
iastrBinaryKey = 52
End If
For iastrBinaryKeyOuterLoop = 24 To 0 Step -1
iachrKeyChars = 0
For iastrBinaryKeyInnerLoop = 14 To 0 Step -1
iachrKeyChars = iachrKeyChars * 256 Xor astrBinaryKey(iastrBinaryKeyInnerLoop + iastrBinaryKey)
astrBinaryKey(iastrBinaryKeyInnerLoop + iastrBinaryKey) = Math.Truncate(iachrKeyChars / 24)
iachrKeyChars = iachrKeyChars Mod 24
Next iastrBinaryKeyInnerLoop
strSQLProductKey = achrKeyChars(iachrKeyChars) + strSQLProductKey
If (iastrBinaryKeyOuterLoop Mod 5) = 0 And iastrBinaryKeyOuterLoop <> 0 Then
strSQLProductKey = "-" + strSQLProductKey
End If
Next iastrBinaryKeyOuterLoop
Catch
strSQLProductKey = "Cannot decode product key."
End Try
GetSQLProductKey = strSQLProductKey
End Function
Function Call SSRS
Code.GetSQLProductKey(Split(Replace(Fields!ProductKey.Value, " ",""), ","), Left(Fields!Version.Value, 2))
I wish to identify if a cell in a worksheet is found within the merged_cells collection returned by openpyxl.
The merged_cells range looks like this (VSCode debugger):
I have the cell reference J31 - which is found in this collection. How would I write a function that returns true if that cell is found in the merged_cells.ranges collection?
for cell in ^^merged_range^^:
if cell==your_special_cell:
return True
^^merged_range^^ must be of type openpyxl.worksheet.cell_range
Further to D.Banakh's answer (+1), try something like this (building upon a previous example I wrote for someone else, since there is little context to your question):
for cell in ws.merged_cells.ranges:
#print(cellRef +' ==> '+ str(cell.min_row) +'/'+ str(cell.max_row) +'/'+ str(cell.min_col) +'/'+ str(cell.max_col))
if (int(cell.min_row) <= int(row) <= int(cell.max_row)) and (int(cell.min_col) <= int(col) <= int(cell.max_col)):
print('Cell ' +cellRef+ ' is a merged cell')
Example within a context:
import re
cellBorders = fnGetCellBorders(ws, cellRef)
if ('T' in cellBorders) or ('L' in cellBorders) or ('R' in cellBorders) or ('B' in cellBorders) or ('M' in cellBorders):
print('Cell has border *OR* is a merged cell and borders cannot be checked')
def getCellBorders(ws, cellRef):
tmp = ws[cellRef].border
brdrs = ''
if tmp.top.style is not None: brdrs += 'T'
if tmp.left.style is not None: brdrs += 'L'
if tmp.right.style is not None: brdrs += 'R'
if tmp.bottom.style is not None: brdrs += 'B'
if (brdrs == '') and ('condTableTopLeftCell' in refs):
if fnIsCellWithinMergedRange(ws, cellRef): brdrs = 'M'
return brdrs
def fnIsCellWithinMergedRange(ws, cellRef):
ans = False
col = fnAlphaToNum(re.sub('[^A-Z]', '', cellRef))
row = re.sub('[^0-9]', '', cellRef)
for cell in ws.merged_cells.ranges:
if (int(cell.min_row) <= int(row) <= int(cell.max_row)) and (int(cell.min_col) <= int(col) <= int(cell.max_col)):
ans = True
return ans
def fnAlphaToNum(ltr):
ab = ["MT", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
return ab.index(ltr)
References:
OpenPyXL - How to query cell borders?
How to detect merged cells in excel with openpyxl
https://bitbucket.org/openpyxl/openpyxl/issues/911/borders-on-merged-cells-are-not-preserved
After hours of work I give up as I do not see the solution anymore.
I therefore ask for your help to create following sequence:
for example given is the start code: 6D082A
The 1st position ("A") is from an array with 16 elements in this sequence:
Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F")
the 3rd to 5th position (082) has values from 000 to 999
the 2nd position ("D") has values from "A" to "Z"
the 1st position (6) has values from 1-9
So the sequence from the example code above is:
6D082A
6D082B
6D082C
..
6D082F
6D0830
6D0831
....
6D083F
6D0840
...
6D999F
6E0000
....
6Z999F
7A0000
....
9Z999F which is the absolut last code in this sequence
Whith all the loops within the counters I am lost!
At the end the user should also enter the given first code and the number of codes he wants.
My last trial was (without any start-code and any variable number of codes to create.
Sub Create_Barcodes_neu2()
Dim strErsterBC As String
Dim intRow As Integer
Dim str6Stelle As Variant
Dim intStart6 As Integer
Dim str6 As String
Dim i As Integer, ii As Integer, Index As Integer
'On Error Resume Next
Dim v As Variant
str6Stelle = Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F") '16 Elemente
strErsterBC = InputBox("Enter the first Barcode.", "Barcode-Generator")
intRow = InputBox("Enter the number of barcodes to create.", "Barcode-Generator")
intStart6 = ListIndex(Mid(strErsterBC, 6, 1), str6Stelle)
str35stelle = CInt(Mid(strErsterBC, 3, 3)) 'Zahl 000-999
str2stelle = Mid(strErsterBC, 2, 1) letters A-Z
str1stelle = Left(strErsterBC, 1)
'Debug.Print str6Stelle(1); vbTab; str6Stelle(2); vbTab; str6Stelle(15); vbTab; str6Stelle(16)
For Z = 0 To 32
ausgabe6 = i + intStart6
i = i + 1
ausgabe35 = str35stelle
ausgabe2 = i3
ausgabe1 = i4
If i = 16 Then
i = 0
i2 = i2 + 1
ausgabe35 = i2 + str35stelle
If i2 = 999 Then
ausgabe35 = 999
i2 = 0
i3 = i3 + 1
If i3 = 26 Then
ausgabe2 = 26
i3 = 1
i4 = i4 + 1
If i4 > 9 Then
MsgBox "Ende"
Exit Sub
End If
End If
End If
End If
st6 = str6Stelle(ausgabe6)
st35 = Format(ausgabe35, "000")
ausgabe2 = Chr(i3)
ausgabe1 = i4
Next Z
End Sub
Hope you can help me in my solution!
Thanks a lot!
Michael
The approach to the right algorithm is to think of a number in the following way:
Let's take a normal decimal 3-digit number. Each digit can take one element of an ordered set of symbols, 0-9.
To add 1 to this number, we exchange the rightmost symbol for the next symbol (2 becomes 3 etc.) - but if it is already the 'highest' possible symbol ("9"),
then reset it to the first possible symbol ("0"), and increase the next digit to the left by one.
So 129 becomes 130, and 199 has two carrying overflows and becomes 200. If we had 999 and tried and inc by one, we'd have a final overflow.
Now this can be easily done with any set of symbols, and they can be completely different for every digit.
In the code, you store the symbol sets for every digit. And the "number" itself is stored as an array of indexes, pointing to which symbol is
used at each position. These indexes can easily be increased.
In case of an overflow for a single digit, the function IncByOne is called recursively for the next position to the left.
This is code for a class clSymbolNumber
Option Explicit
' must be a collection of arrays of strings
Public CharacterSets As Collection
' <code> must contain integers, the same number of elements as CharacterSets
' this is the indices for each digit in the corresponding character-set
Public code As Variant
Public overflowFlag As Boolean
Public Function IncByOne(Optional position As Integer = -1) As Boolean
IncByOne = True
If position = -1 Then position = CharacterSets.Count - 1
' overflow at that position?
If code(position) = UBound(CharacterSets(position + 1)) Then
If position = 0 Then
overflowFlag = True
IncByOne = False
Exit Function
Else
' reset this digit to lowest symbol
code(position) = 0
' inc the position left to this
IncByOne = IncByOne(position - 1)
Exit Function
End If
Else
code(position) = code(position) + 1
End If
End Function
Public Sub class_initialize()
overflowFlag = False
Set CharacterSets = New Collection
End Sub
Public Function getCodeString() As String
Dim i As Integer
Dim s As String
s = ""
For i = 0 To UBound(code)
s = s & CharacterSets(i + 1)(code(i))
Next
getCodeString = s
End Function
Testing sub in a worksheet module - this outputs all possible "numbers" with the given test data.
Sub test()
Dim n As New clSymbolNumber
n.CharacterSets.Add Array("1", "2", "3")
n.CharacterSets.Add Array("a", "b")
n.CharacterSets.Add Array("A", "B", "C", "D")
n.CharacterSets.Add Array("1", "2", "3")
' start code (indexes)
n.code = Array(0, 0, 0, 0)
' output all numbers until overflow
Dim row As Long
row = 2
Me.Columns("A").ClearContents
While Not n.overflowFlag
Me.Cells(row, "A") = n.getCodeString
n.IncByOne ' return value not immediately needed here
row = row + 1
DoEvents
Wend
MsgBox "done"
End Sub
I'm not sure if this is what you're looking for:
Option Explicit
Const MAX_FIRST_DEC_NUMBER As Integer = 9
Const MAX_MIDDLE_DEC_NUMBER As Integer = 999
Const MAX_LAST_HEX_NUMBER As Long= &HF
Sub Makro()
Dim codes() As String
Dim startCode As String
Dim numOfBarcodes As Integer
startCode = "0A0000" ' Starting with the "lowest" barcode
' Maximum number of barcodes = 4,160,000 because:
'0-9' * 'A-Z' * '0-9' * '0-9' * '0-9' * 'A-F'
numOfBarcodes = CLng(10) * CLng(26) * CLng(10) * CLng(10) * CLng(10) * CLng(16)
codes = CreateBarcodes(startCode , numOfBarcodes)
Dim i As Integer
For i = 0 To numOfBarcodes - 1
Debug.Print codes(i)
Next
End Sub
' NOTE: Given "9Z999F" as start code will give you a numberOfBarcodes-sized array with
' one valid barcode. The rest of the array will be empty. There is room for improvement.
Function CreateBarcodes(ByVal start As String, ByVal numberOfBarcodes As Long) As String()
' TODO: Check if "start" is a valid barcode
' ...
' Collect barcodes:
Dim firstDecNumber As Integer
Dim char As Integer
Dim middleDecNumber As Integer
Dim lastLetter As Integer
ReDim barcodes(0 To numberOfBarcodes - 1) As String
For firstDecNumber = Left(start, 1) To MAX_FIRST_DEC_NUMBER Step 1
For char = Asc(Mid(start, 2, 1)) To Asc("Z") Step 1
For middleDecNumber = CInt(Mid(start, 3, 3)) To MAX_MIDDLE_DEC_NUMBER Step 1
For lastLetter = CInt("&H" + Mid(start, 6, 1)) To MAX_LAST_HEX_NUMBER Step 1
numberOfBarcodes = numberOfBarcodes - 1
barcodes(numberOfBarcodes) = CStr(firstDecNumber) + Chr(char) + Format(middleDecNumber, "000") + Hex(lastLetter)
If numberOfBarcodes = 0 Then
CreateBarcodes = barcodes
Exit Function
End If
Next
Next
Next
Next
CreateBarcodes = barcodes
End Function
Output:
9Z999F
9Z999E
9Z999D
...
1A0001
1A0000
0Z999F
0Z999E
...
0B0002
0B0001
0B0000
0A999F
0A999E
...
0A0011
0A0010
0A000F
0A000E
...
0A0003
0A0002
0A0001
0A0000
I just looking how to use LINQ for grouping a list.
Class Item
Public col1 As String
Public col2 As String
Public col3 As String
Public description As String
Public Sub New(ByVal col1 As String, ByVal col2 As String,
ByVal col3 As String, ByVal description As String)
Me.col1 = col1
Me.col2 = col2
Me.col3 = col3
Me.description = description
End Sub
End Class
Dim ItemList As New List(Of Item)
ItemList.Add(New Item("A", "A", "A", "1"))
ItemList.Add(New Item("A", "A", "A", "2"))
ItemList.Add(New Item("A", "B", "A", "3"))
ItemList.Add(New Item("A", "B", "A", "4"))
ItemList.Add(New Item("A", "B", "B", "5"))
ItemList.Add(New Item("A", "B", "C", "6"))
Result should be list of 4 items:
'[0] = "A", "A", "A", "1 2"
'[1] = "A", "B", "A", "3 4"
'[2] = "A", "B", "B", "5"
'[3] = "A", "B", "C", "6"
If I understand your requirement to group by the 3 columns and join their descriptions, the following LINQ statement should work:
var query = from item in ItemList
group item by
new { Col1 = item.col1, Col2 = item.col2, Col3 = item.col3 }
into g
select new
{
Col1 = g.Key.Col1,
Col2 = g.Key.Col2,
Col3 = g.Key.Col3,
Description = String.Join(" ", g.Select(xx => xx.description))
};
Class Item
...
Public ReadOnly Property id As String
Get
Return col1 & "_" & col2 & "_" & col3
End Get
End Property
End Class
Dim groups = ItemList.GroupBy(Function(item) item.id)
Dim result = From g in groups
Select New Item(g(0).col1, g(0).col2, g(0).col3,
String.Join(" "c, g.Select(Function(i) i.description)))