Get next string following array of char - arrays

I have an Array of chars, which is completely random except that every character occurs at most once.
I also have a string containing only characters that are present in the array. I want this string to be "counted upwards" (if that makes sense), like "111" becomes "112", or "aaa" becomes "aab".
Let´s say the Array of chars contains 1, 2, and 3. The example above works, but when the string is "333" (should become "1111"), my function returns an empty - or wrong - string.
If I call the function again, providing the wrong string, after a few times it returns the correct value ("1111").
Why does this happen?
This is my function:
Public Function getNextString(ByVal currentStr As String, ByVal pattern() As Char) As String
'currentStr is the string which I want to count upwards, pattern() is the array of chars
Dim nextStr As String = ""
Dim currentStrArray() As Char = currentStr.ToCharArray
Dim currenStrPosition As Integer = currentStrArray.Length - 1
Dim finished As Boolean = False
Do Until finished = True
Dim newPosition As Integer = getPositionInArray(currentStrArray(currentStrPosition)) 'this is a custom function, should be self-explaining
If newPosition = Nothing Then Return Nothing
newPosition += 1
Try
currentStrArray(currenStrPosition) = pattern(newPosition)
finished = True
Catch ex As IndexOutOfRangeException
currentStrArray(currentStrPosition) = pattern(0)
currentStrPosition -= 1
End Try
If currentStrPosition < 0 Then
nextStr = pattern(0)
finished = True
End If
Loop
For i As Integer = 0 To currentStrArray.Length - 1
nextStr = nextStr & currentStrArray(i)
Next
Return nextStr
End Function
Any ideas?
EDIT:
As an example, I have the array {"1","2","3"}. My string is first "111". I want to test these strings hashsums. After testing that string, I need the next string, "112". Then, "113", "121", "122", and so on. When the string reaches "333" and the string is not the one I'm looking for, it was obviously no string with only 3 characters (all 3-character-combinations possible with the array have been tried). So I need to start again using 4 characters. That´s why "333" is supposed to become "1111".
Hope this helps.
EDIT #2:
I found the error. I redimensioned my array incorrectly, so the last index was empty. This made my strings look weird. Thank you all for your working solutions, have a good day!

Well, I would convert to a number, add 1 and then convert back to a string.
Convert the string to a number:
Function ConvertStringToNumber(input As String, pattern As Char()) As Integer
Dim number As Integer = 0
Dim charDigits = pattern.ToList()
Dim numberBase = charDigits.Count
For i As var = 0 To input.Length - 1
Dim digit = charDigits.IndexOf(input(input.Length - 1 - i))
If digit <> -1 Then
number += digit * CInt(Math.Pow(numberBase, i))
End If
Next
Return number
End Function
Convert the number back to a string:
Function convertNumberToString(number As Integer, pattern As Char()) As String
Dim charDigits = pattern.ToList()
Dim numberBase = charDigits.Count
Dim buffer = New Stack(Of Char)()
'var j = buffer.Length;
While number > 0
buffer.Push(charDigits(number Mod numberBase))
number = number / numberBase
End While
Dim sb = New StringBuilder()
While buffer.Count > 0
sb.Append(buffer.Pop())
End While
Return sb.ToString()
End Function
Now that you have conversion functions, all you have to do is something like this:
Function getNextString(ByVal currentStr As String, ByVal pattern() As Char) As String
Dim number = ConvertStringToNumber(currentStr, pattern)
number += 1
Return convertNumberToString(number, pattern)
End Function

If I understand correctly you want to increment in a specific base (length of your array). What you need is a mapping function that maps your array chars to their respective numbers, then convert from your base to decimal, increment, convert back and remap.
Can you check if this link helps? Quickest way to convert a base 10 number to any base in .NET?
I just wrote the following in c#, it seems to work.
static void Main(string[] args)
{
char[] definition = new char[] { 'a', 'b', 'c', 'd', '9', 'x', 'y', 'z', '1', '2', '3'};
string helperstring = new String(definition);
int basenumber = definition.Length;
string mynumberasstring = "333";
Console.WriteLine(mynumberasstring);
int correspondingdecimal = 0;
for (int i = 0; i < mynumberasstring.Length; i++)
{
char x = mynumberasstring[mynumberasstring.Length - i - 1];
int index = helperstring.IndexOf(x);
int magnitude = 1;
for (int j = 0; j < i; j++)
magnitude *= basenumber;
Console.WriteLine(x + " -> " + index);
correspondingdecimal += magnitude * index;
}
Console.WriteLine(correspondingdecimal + " -> " + ++correspondingdecimal);
List<int> indicesofnewnumber = new List<int>();
int newmagnitude = basenumber;
while(correspondingdecimal > 0)
{
int div = correspondingdecimal / basenumber;
int remainder = correspondingdecimal % basenumber;
Console.WriteLine("{0} -> {1} ; {2}", correspondingdecimal, div, remainder);
indicesofnewnumber.Add(remainder);
correspondingdecimal = div;
}
string newnumberasstring = "";
for (int i = 0; i < indicesofnewnumber.Count; i++)
newnumberasstring += definition[indicesofnewnumber[indicesofnewnumber.Count - 1 - i]];
Console.WriteLine(newnumberasstring);
Console.ReadLine();
}

Here's the smallest code that I can think of to convert a number into an arbitrary base with arbitrary digits:
Dim convert As Func(Of Integer, Char(), String) = Nothing
convert = Function (n, cs) _
If(n \ cs.Length = 0, "", convert(n \ cs.Length, cs)) + cs(n Mod cs.Length)
So, to convert 4 to binary I could do convert(4, { "0"c, "1"c }) and I would get 100.
As a sanity check if I view the first 32 (starting from zero) binary numbers using String.Join(", ", Enumerable.Range(0, 32).Select(Function (n) convert(n, { "0"c, "1"c }))) and I get this:
0, 1, 10, 11, 100, 101, 110, 111, 1000, 1001, 1010, 1011, 1100, 1101, 1110, 1111, 10000, 10001, 10010, 10011, 10100, 10101, 10110, 10111, 11000, 11001, 11010, 11011, 11100, 11101, 11110, 11111
Or the first 102 decimal numbers starting from zero with String.Join(", ", Enumerable.Range(0, 102).Select(Function (n) convert(n, "0123456789".ToCharArray()))) I get this:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101
So I can now use the same kind of code to get the first 50 numbers from the digits { "1"c, "2"c, "3"c } using String.Join(", ", Enumerable.Range(0, 50).Select(Function (n) convert(n, "123".ToCharArray()))) and I get this:
1, 2, 3, 21, 22, 23, 31, 32, 33, 211, 212, 213, 221, 222, 223, 231, 232, 233, 311, 312, 313, 321, 322, 323, 331, 332, 333, 2111, 2112, 2113, 2121, 2122, 2123, 2131, 2132, 2133, 2211, 2212, 2213, 2221, 2222, 2223, 2231, 2232, 2233, 2311, 2312, 2313, 2321, 2322
This is the correct "counting" using the digits { "1"c, "2"c, "3"c }. So, it would be correct to say that "333" + 1 = "2111" in this numbering system. This is the same as saying 999 + 1 = 1000 in our decimal system - it clearly doesn't go from 999 + 1 = 0000 which is the implication that "333" + 1 = "1111" would mean in this "123" system. Strictly speaking I should have written "333" + "2" = "2111" (since "2" represents 1).
If you want all combinations then you would need to pad the strings to the left with the "zero" character - in this case 1. Then this code:
String.Join(", ", _
Enumerable _
.Range(0, 500) _
.Select(Function (n) convert(n, "123".ToCharArray()).PadLeft(4, "1"c)) _
.Where(Function (x) x.Length = 4))
...gives the following 81 numbers:
1111, 1112, 1113, 1121, 1122, 1123, 1131, 1132, 1133, 1211, 1212, 1213, 1221, 1222, 1223, 1231, 1232, 1233, 1311, 1312, 1313, 1321, 1322, 1323, 1331, 1332, 1333, 2111, 2112, 2113, 2121, 2122, 2123, 2131, 2132, 2133, 2211, 2212, 2213, 2221, 2222, 2223, 2231, 2232, 2233, 2311, 2312, 2313, 2321, 2322, 2323, 2331, 2332, 2333, 3111, 3112, 3113, 3121, 3122, 3123, 3131, 3132, 3133, 3211, 3212, 3213, 3221, 3222, 3223, 3231, 3232, 3233, 3311, 3312, 3313, 3321, 3322, 3323, 3331, 3332, 3333
...and 81 is the total number of combinations as 3 x 3 x 3 x 3 = 81.
Here are the pair of functions to convert both ways:
Function Convert(number As Integer, digits As Char()) As String
Dim r = digits(number Mod digits.Length).ToString()
If number \ digits.Length <> 0 Then
r = Convert(number \ digits.Length, digits) + r
End If
Return r
End Function
Function Convert(number As String, digits As Char()) As Integer
Dim r = Array.IndexOf(digits, number(0))
If number.Substring(1).Length > 0 Then
r = r * digits.Length + Convert(number.Substring(1), digits)
End If
Return r
End Function

Related

macro word "VBA error too many line continuations"

I have a long variant array. I was trying to break it with (, _) but I still got the same error.
for example:
arr as variant
arr = array(15,54,10,15,0,0,0,51,12,36,23,15,52,115,132,16,13,18,0,0,0,0,0,0,0,2,0,51,13, _,
,1,25,15,31,81,35,64,31,,0,0,0,0,2,0,5,1,4,3,150,1,91,156,151,51,150,1,0,0,0, _ , ...
maybe the array length is 30 lines.
any help on how to solve this error?
Can't you take your data another way? or do you need to generate random numbers? I think it will take more explanation on what you plan to do to help yourself.
So far the only thing I have found is that your array is filled with a function. I don't know if that will satisfy you as an answer.
Sub main()
Dim arr() As Variant
arr = Array(15, 54)
Call AddArray(arr, Array(15, 54, 10, 15, 0, 0, 0, 51, 12, 36, 23, 15, 52, 115, 132, 16, 13, 18, 0, 0, 0, 0, 0, 0, 0, 2, 0, 51, 13))
Call AddArray(arr, Array(1, 25, 15, 31, 81, 35, 64, 31, , 0, 0, 0, 0, 2, 0, 5, 1, 4, 3, 150, 1, 91, 156, 151, 51, 150, 1, 0, 0, 0))
End Sub
Function AddArray(ByRef arr As Variant, ByRef arrAdd As Variant) As Variant
' "UBound(arr) - LBound(arr) + 1" : Is the calcul for get length of array
LengthArr = UBound(arr) - LBound(arr) + 1
LengthArrAdd = UBound(arrAdd) - LBound(arrAdd) + 1
'Calcul the length of futur array
LengthNewArr = LengthArr + LengthArrAdd - 1
'Redimension the arr
ReDim Preserve arr(LBound(arr) To LengthNewArr)
'Fill the arr with i who start to new espace of array at end
For i = LengthArr To LengthNewArr
arr(i) = arrAdd(i - LengthArr)
Next
'AddArray = arr
End Function
result : arr(0) = 15, arr(1) = 54, ..., ..., arr(59) = 0, arr(60) = 0

Replace random elements of Array

I have two arrays of same length
import scala.util.Random
val length = 10
val x = 60 // Selection percentage
val rnd = new Random
var arrayOne = Array.fill(length)(rnd .nextInt(100))
arrayOne: Array[Int] = Array(8, 77, 11, 19, 17, 73, 5, 18, 45, 69)
val arrayTwo = Array.fill(length)(rnd .nextInt(100))
arrayTwo: Array[Int] = Array(96, 21, 85, 70, 28, 5, 31, 56, 27, 76)
I can select first x percent element from arrayTwo and those selected elements can replace first x percent elements of arrayOne in the following way.
arrayOne = arrayTwo.take((length * x / 100).toInt) ++ arrayOne.drop((length * x / 100).toInt)
arrayOne: Array[Int] = Array(96, 21, 85, 70, 28, 5, 5, 18, 45, 69)
Now I want to select random x percent elements from arrayTwo and that selected elements will replace random x percent elements of arrayOne. How can I do this?
You can exchange every item with a probability x:
val x = 60D
val exchanged = arrayOne.indices
.map(x => if(math.random > x / 100) arrayOne(x) else arrayTwo(x))
But that way you have no guarantee that (length * x / 100).toInt elements will be from arrayTwo. To achieve that I would go for iterative / recursive algorithm, where I'd pick random index until I have as much as I want.
You can do it via Random.shuffle:
scala> val randSet = Random.shuffle(arrayOne.indices.toBuffer).take((arrayOne.length * x / 100).toInt).toSet
randSet: scala.collection.immutable.Set[Int] = HashSet(0, 6, 9, 3, 8, 4)
scala> val randMerged = arrayOne.indices.map(i => if(randSet(i)) arrayTwo(i) else arrayOne(i))
randMerged: IndexedSeq[Int] = Vector(96, 77, 11, 70, 28, 73, 31, 18, 27, 76)
The randSet will take x percent indices randomly.
If you do not care the number's position, there is a simple one:
scala> val size = (arrayOne.length * x / 100).toInt
size: Int = 6
scala> Random.shuffle(arrayTwo).take(size) ++ Random.shuffle(arrayOne).drop(size)
res11: scala.collection.mutable.ArraySeq[Int] = ArraySeq(76, 85, 28, 56, 21, 27, 69, 45, 17, 77)

Binary Search a non-existing number in a sorted array, return a larger negative number than -1

When the search number is 12, why does it return -6 instead of -1?
int[] list = {2, 4, 7, 10, 11, 45, 50, 59, 60, 66, 69, 70, 79};
System.out.println("1. Index is " + Arrays.binarySearch(list, 11));
System.out.println("2. Index is " + Arrays.binarySearch(list, 12));
Result:
1. Index is 4
2. Index is -6
Update
Now I understand because
Arrays.binarySearch will return
(-(insertion point) - 1)
if the number is not in the array.
i.e
12 is at insertion of 5, so return (-(5) - 1) = -6.
Thanks for the help.
You may refer to the Javadoc : Arrays.binarySearch(int[] a,int key)
It returns :
index of the search key, if it is contained in the array;
otherwise : (-(insertion point) - 1).
Here the insertion point would be :
int[] list = {2, 4, 7, 10, 11, 45, 50, 59, 60, 66, 69, 70, 79};
// 1^ 2^ 3^ 4^ 5^
The position 5 so (-5-1) = -6
Extracted from BinarySearch
Return value:
This method returns index of the search key, if it is contained in the array, else it returns (-(insertion point) - 1). The insertion point is the point at which the key would be inserted into the array: the index of the first element greater than the key, or a.length if all elements in the array are less than the specified key.
From the return value explanation, it returns the negation of the position the element will be in the array (that is -5) minus 1, which would be -6.
This is a common return type for BinarySearch() methods.
If you would like to print the index of an integer a :
int[] list = {2, 4, 7, 10, 11, 45, 50, 59, 60, 66, 69, 70, 79};
int a =12; //Value can be updated or read through Scanner
int temp = Arrays.binarySearch(list,a);
if(temp>=0){
System.out.println("Index of a is : " + temp)
}else{
System.out.println("Insertion point for a is : " + (-1)*(temp+1);
}

Gzip sequence of tuples and then unzip again into sequence of tuples - issue when unzipping the sequence

I have a sequence of Tuples that I need to gzip for storage. Afterwards I want to be able to extract the compressed content, decompress it and then get the Sequence of tuples back.
I use the following code for de/compressing:
def unzip(x: Array[Byte]) : String = {
val inputStream = new GZIPInputStream(new ByteArrayInputStream(x))
val output = scala.io.Source.fromInputStream(inputStream).mkString
return output
}
def gzip(input: Array[Byte]): Array[Byte] = {
val bos = new ByteArrayOutputStream(input.length)
val gzip = new GZIPOutputStream(bos)
gzip.write(input)
gzip.close()
val compressed = bos.toByteArray
bos.close()
compressed
}
As taken from this source https://gist.github.com/owainlewis/1e7d1e68a6818ee4d50e .
Then my routine more or less is the following:
val arr = Seq(("a",1),("b",2))
val arr_bytes = arr.toString.getBytes
val comp = compress(arr_bytes)
val x = unzip(comp)
The output is the following:
arr: Seq[(String, Int)] = List((a,1), (b,2))
arr_bytes: Array[Byte] = Array(76, 105, 115, 116, 40, 40, 97, 44, 49, 41, 44, 32, 40, 98, 44, 50, 41, 41)
comp: Array[Byte] = Array(31, -117, 8, 0, 0, 0, 0, 0, 0, 0, -13, -55, 44, 46, -47, -48, 72, -44, 49, -44, -44, 81, -48, 72, -46, 49, -46, -44, 4, 0, 35, 120, 118, -118, 18, 0, 0, 0)
x: String = List((a,1), (b,2))
The problem is x is now a String that has the format from above (with the word List contained as well).
For example:
x.toList
res174: List[Char] = List(L, i, s, t, (, (, a, ,, 1, ), ,, , (, b, ,, 2, ), ))
My question is, how do I decompress my exact sequence back, or how do I make x into my previous sequence again?
Solved it using the play api json library for storing the content in json objects:
val arr = Json.toJson(Array(Json.obj("name"-> "Bran", "age" -> 13),Json.obj("name"-> "Jon", "age" -> 18)))
val arr_bytes = arr.toString().getBytes
val comp = compress(arr_bytes)
val x= unzip(comp)
val json = Json.parse(x)

Printing array in Scala

I am having problem with most basic Scala operation and it is making me crazy.
val a = Array(1,2,3)
println(a) and result is [I#1e76345
println(a.toString()) and result is [I#1e76345
println(a.toString) and result is [I#1e76345
Can anyone tell me how to print array without writing my own function for doing that because that is silly. Thanks!
mkString will convert collections (including Array) element-by-element to string representations.
println(a.mkString(" "))
is probably what you want.
You can do the normal thing (see either Rex's or Jiri's answer), or you can:
scala> Array("bob","sue")
res0: Array[String] = Array(bob, sue)
Hey, no fair! The REPL printed it out real nice.
scala> res0.toString
res1: String = [Ljava.lang.String;#63c58252
No joy, until:
scala> runtime.ScalaRunTime.stringOf(res0)
res2: String = Array(bob, sue)
scala> runtime.ScalaRunTime.replStringOf(res0, res0.length)
res3: String =
"Array(bob, sue)
"
scala> runtime.ScalaRunTime.replStringOf(res0, 1)
res4: String =
"Array(bob)
"
I wonder if there's a width setting in the REPL. Update: there isn't. It's fixed at
val maxStringElements = 1000 // no need to mkString billions of elements
But I won't try billions:
scala> Array.tabulate(100)(identity)
res5: Array[Int] = Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99)
scala> import runtime.ScalaRunTime.replStringOf
import runtime.ScalaRunTime.replStringOf
scala> replStringOf(res5, 10)
res6: String =
"Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
"
scala> res5.take(10).mkString(", ")
res7: String = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
Wait, let's make that:
scala> res5.take(10).mkString("Array(", ", ", ")")
res8: String = Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
This might be obvious:
scala> var vs = List("1")
vs: List[String] = List(1)
scala> vs = null
vs: List[String] = null
scala> vs.mkString
java.lang.NullPointerException
So instead:
scala> import runtime.ScalaRunTime.stringOf
import runtime.ScalaRunTime.stringOf
scala> stringOf(vs)
res16: String = null
Also, an array doesn't need to be deep to benefit from its stringPrefix:
scala> println(res0.deep.toString)
Array(bob, sue)
Whichever method you prefer, you can wrap it up:
implicit class MkLines(val t: TraversableOnce[_]) extends AnyVal {
def mkLines: String = t.mkString("", EOL, EOL)
def mkLines(header: String, indented: Boolean = false, embraced: Boolean = false): String = {
val space = "\u0020"
val sep = if (indented) EOL + space * 2 else EOL
val (lbrace, rbrace) = if (embraced) (space + "{", EOL + "}") else ("", "")
t.mkString(header + lbrace + sep, sep, rbrace + EOL)
}
}
But arrays will need a special conversion because you don't get the ArrayOps:
implicit class MkArrayLines(val a: Array[_]) extends AnyVal {
def asTO: TraversableOnce[_] = a
def mkLines: String = asTO.mkLines
def mkLines(header: String = "Array", indented: Boolean = false, embraced: Boolean = false): String =
asTO.mkLines(header, indented, embraced)
}
scala> Console println Array("bob","sue","zeke").mkLines(indented = true)
Array
bob
sue
zeke
Here are two methods.
One is to use foreach:
val a = Array(1,2,3)
a.foreach(println)
The other is to use mkString:
val a = Array(1,2,3)
println(a.mkString(""))
If you use list instead, toString() method prints the actual elenents (not the hashCode)
var a = List(1,2,3)
println(a)
or
var a = Array(1,2,3)
println(a.toList)
For a simple Array of Ints like this, we can convert to a Scala List (scala.collection.immutable.List) and then use List.toString():
var xs = Array(3,5,9,10,2,1)
println(xs.toList.toString)
// => List(3, 5, 9, 10, 2, 1)
println(xs.toList)
// => List(3, 5, 9, 10, 2, 1)
If you can convert to a List earlier and do all your operations with Lists, then you'll probably end up writing more idiomatic Scala, written in a functional style.
Note that using List.fromArray is deprecated (and has been removed in 2.12.2) .
The method deep in ArrayLike recursively converts multidimensional arrays to WrappedArray, and overwrites a long prefix "WrappedArray" with "Array".
def deep: scala.collection.IndexedSeq[Any] = new scala.collection.AbstractSeq[Any] with scala.collection.IndexedSeq[Any] {
def length = self.length
def apply(idx: Int): Any = self.apply(idx) match {
case x: AnyRef if x.getClass.isArray => WrappedArray.make(x).deep
case x => x
}
override def stringPrefix = "Array"
}
Usage:
scala> val arr = Array(Array(1,2,3),Array(4,5,6))
arr: Array[Array[Int]] = Array(Array(1, 2, 3), Array(4, 5, 6))
scala> println(arr.deep)
Array(Array(1, 2, 3), Array(4, 5, 6))
Rather than manually specifying all the parameters for mkString yourself (which is a bit more verbose if you want to add start and end markers in addition to the delimiter) you can take advantage of the WrappedArray class, which uses mkString internally. Unlike converting the array to a List or some other data structure, the WrappedArray class just wraps an array reference, it's created in effectively constant time.
scala> val a = Array.range(1, 10)
a: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8, 9)
scala> println(a)
[I#64a2e69d
scala> println(x: Seq[_]) // implicit
WrappedArray(a, b, c, d)
scala> println(a.toSeq) // explicit
WrappedArray(1, 2, 3, 4, 5, 6, 7, 8, 9)

Resources