permutations gone wrong - vb.net

I have written code to implement an algorithm I found on string permutations. What I have is an arraylist of words ( up to 200) and I need to permutate the list in levels of 5. Basically group the string words in fives and permutated them. What I have takes the first 5 words generates the permutations and ignores the rest of the arraylist?
Any ideas appreciated.
Private Function permute(ByVal chunks As ArrayList, ByVal k As Long) As ArrayList
ReDim ItemUsed(k)
pno = 0
Permutate(k, 1)
Return chunks
End Function
Private Shared Sub Permutate(ByVal K As Long, ByVal pLevel As Long)
Dim i As Long, Perm As String
Perm = pString ' Save the current Perm
' for each value currently available
For i = 1 To K
If Not ItemUsed(i) Then
If pLevel = 1 Then
pString = chunks.Item(i)
'pString = inChars(i)
Else
pString = pString & chunks.Item(i)
'pString += inChars(i)
End If
If pLevel = K Then 'got next Perm
pno = pno + 1
SyncLock outfile
outfile.WriteLine(pno & " = " & pString & vbCrLf)
End SyncLock
outfile.Flush()
Exit Sub
End If
' Mark this item unavailable
ItemUsed(i) = True
' gen all Perms at next level
Permutate(K, pLevel + 1)
' Mark this item free again
ItemUsed(i) = False
' Restore the current Perm
pString = Perm
End If
Next
K above is = to 5 for the number of words in one permutation but when I change the for loop to the arraylist size I get an error of index out of bounds

Index out of bounds error usually happens when you start the loop from 1 to length. The the for loop as following.
For i = 0 to array.length - 1

You will get this error.
When you do
For i = 1 To K
The last value of i will be the size of your array.
chunks.Item(i)
Will crash when i equals the size of the array since the index starts at 0.
I would suggest you change your for loop to
For i = 0 To K - 1
Or you change the way you access the values in your arrays to
chunks.Item(i-1)

C++ Permutation
#include <stdio.h>
void print(const int *v, const int size)
{
if (v != 0)
{
for (int i = 0; i < size; i++)
{
printf("%4d", v[i] );
}
printf("\n");
}
} // print
void permute(int *v, const int start, const int n)
{
if (start == n-1) {
print(v, n);
}
else {
for (int i = start; i < n; i++) {
int tmp = v[i];
v[i] = v[start];
v[start] = tmp;
permute(v, start+1, n);
v[start] = v[i];
v[i] = tmp;
}
}
}
main()
{
int v[] = {1, 2, 3, 4};
permute(v, 0, sizeof(v)/sizeof(int));
}

Related

Converting Random Pairing Function from VBA to GAS

I've been working to create a random pairing algorithm for my bass club. The idea is to pair a value in Column A (Boaters) with a value in Column B (non-boaters). If there are no more non-boaters, any remaining boaters should be paired unless only one unpaired boater remains.
I found some VBA code online, which works fine in Excel, but all of my club's stuff is in Google Sheets and I'd like to have the same pairing function in GAS.
I've tried my best to convert the VBA code to GAS, but honestly, I have some experience with VBA and I'm still a relative novice at GAS, although I'm learning.
I've pasted the two VBA functions below, followed by the GAS conversion I've been working on. The comments show the areas where I'm having trouble, particularly with the called sorting function (vSortM), although I'd welcome a second set of eyes to make sure I haven't incorrectly coded something else.
Can anyone advise if I am performing the conversion from VBA to GAS correctly?
Pairing Algorithm in VBA that I found online:
Option Explicit
Sub test()
Dim Boters(), NonBoters(), i As Long, x As Long
Boters = Range("a1", Range("a" & Rows.Count).End(xlUp)).Value
Redim Preserve Boters(1 To UBound(Boters), 1 To 2)
NonBoters = Range("b1", Range("b" & Rows.Count).End(xlUp)).Value
Redim Preserve NonBoters(1 To UBound(NonBoters), 1 To 2)
Randomize
For i = 1 To UBound(Boters)
Boters(i, 2) = Rnd
Next
For i = 1 To UBound(NonBoters)
NonBoters(i, 2) = Rnd
Next
VSortM Boters, 1, UBound(Boters), 2
VSortM NonBoters, 1, UBound(NonBoters), 2
x = Application.Min(UBound(Boters), UBound(NonBoters))
With Cells(1, 4).Resize(x, 2)
.CurrentRegion.ClearContents
.Columns(1).Value = Boters
.Columns(2).Value = NonBoters
End With
If x < UBound(Boters) Then
For i = x + 1 To UBound(Boters) Step 2
If i + 1 > UBound(Boters) Then Exit For
Cells(i, 4).Value = Boters(i, 1)
Cells(i, 5).Value = Boters(i + 1, 1)
Next
End If
End Sub
Private Sub VSortM(ary, LB, UB, ref)
Dim M As Variant, i As Long, ii As Long, iii As Long, temp
i = UB: ii = LB
M = ary(Int((LB + UB) / 2), ref)
Do While ii <= i
Do While ary(ii, ref) < M
ii = ii + 1
Loop
Do While ary(i, ref) > M
i = i - 1
Loop
If ii <= i Then
For iii = LBound(ary, 2) To UBound(ary, 2)
temp = ary(ii, iii)
ary(ii, iii) = ary(i, iii): ary(i, iii) = temp
Next
ii = ii + 1: i = i - 1
End If
Loop
If LB < i Then VSortM ary, LB, i, ref
If ii < UB Then VSortM ary, ii, UB, ref
End Sub
My attempt at converting the Pairing Algorithm in GAS
function test() {
//Get values for Column A and Column B starting at Row 5
var ssMatch = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Pairings');
var bRange = ssMatch.getRange("A5:A").getValues();
var nBRange = ssMatch.getRange("B5:B").getValues();
//Determine length with data to exclude blansk
var bLast = bRange.filter(String).length;
var nBLast = nBRange.filter(String).length;
//Get values for boaters & nBoaters without blanks
var boaters = ssMatch.getRange(5,1,bLast).getValues();
var nBoaters = ssMatch.getRange(5,2,nBLast).getValues();
// Populate boaters & nBoaters arrays using random numbers
for (var i = 0; i < bLast; i++) {
boaters[i][1] = Math.random();
Logger.log(boaters);
}
for (var j = 0; j<nBLast; j++) {
nBoaters[j][1] = Math.random();
Logger.log(nBoaters);
}
vSortM (boaters, 1, bLast, 1);
vSortM (nBoaters, 1, nBLast, 1);
//Determine whether there are more boaters or non-boaters
var x = Min(bLast, nBLast);
//Write boater & nBoater values in Columns
//NEED SOME HELP HERE: Certain this isn't correct for GAS
Cells(1,4).Resize(x, 2);
Cells.CurrentRegion.ClearContents;
Cells.Columns(1).setValues(boaters);
Cells.Columns(2).setValues(nBoaters);
//If no more nBoaters, pair remaining unpaired boaters
if (x < bLast) {
for (var i = x + 1; i<bLast; i = i + 2) {
if (i + 1 > bLast) { break;}
else {
//THINK I DID THIS RIGHT, BUT NOT SURE
ssMatch.getRange(i,4).setValue(boaters[i][0]);
ssMatch.getRange(i,5).setValue(boaters[i+1][0]);
}
}
}
}
//Having some trouble converting this from VBA to GAS
// not sure how to deal with the ary parameter and m statement
function vSortM(ary, lB, uB, ref) {
var temp = 0;
var i = uB;
var ii = lB;
var m = [parseInt((lB + uB) / 2), ref];
while (ii <= i);{
while ([ii, ref] < m); {
ii++;
while ([i, ref] > m); {
i--;
}
if (ii <= i); {
for (var iii = 0; i<=(ary, 2);) {
temp = [ii, iii];
[ii, iii] = [i, iii];
[i, iii] = temp;
}
ii++;
i--;
}
}
if (lB < i) {
vSortM(ary, lB, i, ref);
}
if (ii < uB) {
vSortM(ary, ii, uB, ref);
}
}
}
First off, I have to agree with the others in the comments. The question is too broad. In https://stackoverflow.com/help/dont-ask it says that questions should be reasonably scoped.
From what I see in your code that you ask for help.
//NEED SOME HELP HERE: Certain this isn't correct for GAS
Cells(1,4).Resize(x, 2);
Cells.CurrentRegion.ClearContents;
Cells.Columns(1).setValues(boaters);
Cells.Columns(2).setValues(nBoaters);
This section is easy to figure out by using the very well written documentation for GAS (always refer to it first before going anywhere else). In GAS you are essentially working with classes (or objects if you will). Here you will want the sheet class to resize the row and column (2 seperate functions) and then a range class (which is retrieved from the sheet class) to clear and set values.
//THINK I DID THIS RIGHT, BUT NOT SURE
ssMatch.getRange(i,4).setValue(boaters[i][0]);
ssMatch.getRange(i,5).setValue(boaters[i+1][0]);
Depends on what you want to accomplish. The syntax here is correct, you set a value for a single cell. Keep in mind that in google sheets it's best to try and batch such calls. So instead of setting a value on a cell by cell basis, you would get a range from A1 to B20 and set all values at once with a 2D array.
Finally you need to clarify what it is the second functions has to do and what it doesn't do right. Perhaps share a minimal example sheet (read here about Minimal, Complete, and Verifiable example)?

multidimensional array linq query

i have 5 dimensional array, when using linq to query, the results are sorted in dimensional way:
array(a)(b)(c)(d)(e) , dimension = 1
using for next:
For e = 0 To dimension - 1
For d = 0 To dimension - 1
For c = 0 To dimension - 1
For b = 0 To dimension - 1
For a = 0 To dimension - 1
listbox.Items.Add(array(a, b, c, d, e).disc)
Next
Next
Next
Next
Next
this would result in:
abcde
00000
10000
01000
...
if i use linq:
listbox.Items.AddRange((From item In array Select item.disc).ToArray)
this would result in:
abcde
00000
00001
00010
...
how can i achieve the first result with linq?
Public Class ArrayExt
Public Shared Function GetFirstFastestEnumerator(Of T)(source As Array) As IEnumerable(Of T)
Dim srcRank = source.Rank
Dim indices = New Integer((srcRank) - 1) {}
Dim len = source.Length
For i = 0 To srcRank - 1
indices(i) = source.GetLowerBound(i)
Next
Dim curRank As Integer = 0
For i = 0 To len - 1
Return CType(source.GetValue(indices), T)
While (curRank < srcRank)
If (indices(curRank) < source.GetUpperBound(curRank)) Then
indices(curRank) = indices(curRank) + 1
curRank = 0
Exit While
Else
indices(curRank) = source.GetLowerBound(curRank)
curRank = curRank + 1
End If
End While
Next
End Function
End Class
You need a custom Iterator to go through the array in the rank order you want, which is opposite the built-in order.
public static class ArrayExt {
public static IEnumerable<T> GetFirstFastestEnumerator<T>(this Array src) {
var srcRank = src.Rank;
var indices = new int[srcRank];
var len = src.Length;
for (var j1 = 0; j1 < srcRank; ++j1)
indices[j1] = src.GetLowerBound(j1);
int curRank = 0;
for (var j1 = 0; j1 < len; ++j1) {
yield return (T)src.GetValue(indices);
while (curRank < srcRank) {
if (indices[curRank] < src.GetUpperBound(curRank)) {
++indices[curRank];
curRank = 0;
break;
}
else {
indices[curRank] = src.GetLowerBound(curRank);
++curRank;
}
}
}
}
}
Which you can use either with LINQ or foreach. Replace arrayType with the class stored in array.
listbox.Items.AddRange((From item In array.GetFirstFastestEnumerator<arrayType>() Select item.disc).ToArray)
Or Visual Basic version:
Public Module Ext
<Extension()> _
Public Iterator Function GetFirstFastestIterator(Of T)(source As Array) As IEnumerable(Of T)
Dim srcRank = source.Rank
Dim indices = New Integer((srcRank) - 1) {}
Dim len = source.Length
For i = 0 To srcRank - 1
indices(i) = source.GetLowerBound(i)
Next
Dim curRank As Integer = 0
For i = 0 To len - 1
Yield CType(source.GetValue(indices), T)
While (curRank < srcRank)
If (indices(curRank) < source.GetUpperBound(curRank)) Then
indices(curRank) = indices(curRank) + 1
curRank = 0
Exit While
Else
indices(curRank) = source.GetLowerBound(curRank)
curRank = curRank + 1
End If
End While
Next
End Function
End Module

VB.net only 32 bytes and less to search

this is a function to search for a byte pattern (in process memory) in an array of bytes.
where SearchFor is the array of bytes to look for. and SearchInis the array of bytes dumped by the ReadProcessMemory external function. this is also done using Wildcard "?".
problem is if the byte pattern length is less or equal to 32 it will search. else return intptr.zero. and im not sure why.
Private Function WildCard(ByVal SearchIn As Byte(), ByVal SearchFor As Byte()) As IntPtr
Dim l As Integer = 0, m = 0
Dim iEnd As Integer = SearchFor.Length
Dim sBytes As Integer() = New Integer(&H100 - 1) {}
Dim i As Integer
For i = 0 To iEnd - 1
If (SearchFor(i) = &H3F) Then
l = (l Or (CInt(1) << ((iEnd - i) - 1)))
End If
Next i
If (l <> 0) Then
Dim j As Integer
For j = 0 To sBytes.Length - 1
sBytes(j) = l
Next j
End If
l = 1
Dim index As Integer = (iEnd - 1)
Do While (index >= 0)
sBytes(SearchFor(index)) = (sBytes(SearchFor(index)) Or l)
index -= 1
l = (l << 1)
Loop
Do While (m <= (SearchIn.Length - SearchFor.Length))
l = (SearchFor.Length - 1)
Dim length As Integer = SearchFor.Length
Dim k As Integer = -1
Do While (k <> 0)
k = (k And sBytes(SearchIn((m + l))))
If (k <> 0) Then
If (l = 0) Then
Return New IntPtr(m)
End If
length = l
End If
l -= 1
k = (k << 1)
Loop
m = (m + length)
Loop
Return IntPtr.Zero
End Function

Splitting a String into Pairs

How would I go on splitting a string into pairs of letter in VB?
for example: abcdefgh
split into: ab cd ef gh
I'll throw my hat in the ring:
Dim test As String = "abcdefgh"
Dim results As New List(Of String)
For i As Integer = 0 To test.Length - 1 Step 2
If i + 1 < test.Length Then
results.Add(test.Substring(i, 2))
Else
results.Add(test.Substring(i))
End If
Next
MessageBox.Show(String.Join(" ", results.ToArray))
The following allows for odd length strings. If the string is zero-length, I'm not sure what you'd want to do, you'll want to address that case.
Dim src As String = "abcdef"
Dim size As Integer
If src.Length > 0 Then
If src.Length Mod 2 = 0 Then
size = (src.Length / 2) - 1
Else
size = ((src.Length + 1) / 2) - 1
End If
Dim result(size) As String
For i = 0 To src.Length - 1 Step 2
If i = src.Length - 1 Then
result(i / 2) = src.Substring(i, 1)
Else
result(i / 2) = src.Substring(i, 2)
End If
Next
End If
In C# you would do like this:
Dictionary<String, String> Split(String input)
{
if (input.Count % 2 == 0)
{
Dictionary<string, string> Pairs = new Dictionary( );
for (int L = 0, R = 1; L < input.Count && R <= input.Count; ++L, ++R)
{
Char
Left = input[L],
Right = input[R];
Pairs.Add(
Left.ToString(),
Right.ToString());
}
}
else
{
throw new NotEvenException( );
}
return Pairs( );
}
void Main()
{
var Pairs = Split("ABCDEFGH");
foreach(string Key in Split("ABCDEFGH"))
{
Console.Write("{0}{1}\n", Key, Pairs[Key]);
}
}
/*
Output:
AB
CD
EF
GH
*/
Now, I know what you think: This isn't what I want! But I say: It is actually, at least partly.
Since I presume you're working in VB.net, the basic structure of what you want performed is outlined in the short snippet above.
For example: The method Count (of the object String) exists in both C# and in VB.
Hope it helps a bit at least!

Developing Fibonacci Series in VB

I am trying to write a code for Fibonacci series in VB, but some of the values in my series are incorrect. Can somebody help me with the code?
Below is what I have so far.
Private Function FibNumber(number As Integer) As Integer
If (number > 2) Then
FibNumber = (FibNumber(number - 2) + FibNumber(number - 1))
Else
FibNumber = 1
End If
End Function
Private Sub command1_click()
Dim x As Integer
x = Text1.Text
Call FibNumber(number)
End Sub
Well, I did a quick search and I came up with the following in the first couple of results:
Private Function FibNumber(number As Integer) As Integer
If (number > 2) Then
FibNumber = (FibNumber(number - 2) + FibNumber(number - 1))
Else
FibNumber = 1
End If
End Function
I know this is way old, but I think the issue could be with how compgeek is calling the function.
Instead of:
Call FibNumber(number)
It should be:
Call FibNumber(x)
My solution:
Private Function FibNumber(number As Integer) As Integer
If (number > 2) Then
FibNumber = (FibNumber(number - 2) + FibNumber(number - 1))
Else
FibNumber = 1
End If
End Function
Private Sub command1_click()
Dim x As Integer
x = Text1.Text
Call FibNumber(number)
End Sub
It's a Java function, and believe me; Fibonacci wont get much more faster or complex than
this particular version. It is optimized to operate at about 100 times faster than the original recursive one.
Tip: You might need to change maxN to extend parameter length!
For example if you want to input numbers between 0 and 199, you must increase the maxN to 200
static final int maxN = 72;
static long knownF[] = new long[maxN];
static long F(int i) {
if (knownF[i] != 0) {
return knownF[i];
}
long t = i;
if (i < 0) {
return 0;
}
if (i > 1) {
t = F(i - 1) + F(i - 2);
}
return knownF[i] = t;
}
Module Module1
Sub Main()
Console.WriteLine("The Fibonacci Series")
Console.WriteLine("Enter how many elements-")
Dim n As Integer = Console.ReadLine
If (n = 1) Then
Dim a As Integer = 1
Console.WriteLine("{0}", a)
Else
Dim a As Integer = 1
Dim b As Integer = 2
Console.WriteLine("{0}", a)
Console.WriteLine("{0}", b)
Dim i As Integer = 1
While (i < n - 1)
Dim c As Integer = a + b
Console.WriteLine(" {0}", c)
a = b
b = c
i = i + 1
End While
End If
Console.ReadKey()
End Sub
End Module