Different ways to create random strings in Scala
http://alvinalexander.com/scala/creating-random-strings-in-scala
When it comes to generating random strings with the scala.util.Randomclass, I haven’t figured out yet how to properly use the
nextString
method. I’ve tried using it in several different ways, but I always get a string of question marks as output, like this:scala> val r = new scala.util.Random(31) r: scala.util.Random = scala.util.Random@7d49fa1e scala> r.nextString(10) res0: String = ??????????
This happens whether I give
Random
a seed value or not, and whether I call nextString
as a static method or not:scala> Random.nextString(5) res1: String = ?????
Update: The solution to this problem is shown in the Comments section below. I’ll update this post when I have more time, but for now I’ll just say that the correct answer is to use this code (and see the comment below):Random.alphanumeric.take(10).mkString
The Random alphanumeric method
Frankly I haven’t really needed this capability, so this unusual behavior hasn’t bothered me enough for me to take time to look into it. Plus, I could always use the
alphanumeric
method as follows to get a random string:scala> val x = Random.alphanumeric x: scala.collection.immutable.Stream[Char] = Stream(Q, ?) scala> x take 10 foreach println Q n m x S Q R e P B
(Note that the
alphanumeric
method returns a Stream, so you need to coerce the Stream to give you some output, as shown in that example. I don’t think I have any tutorials out here about Scala Streams just yet, but I do cover them in detail in the Scala Cookbook.)Generating a random string as an exercise
On one particularly cold night in Alaska back in December (it’s January now as I write this) I got bored and decided to write my own random string method. As I started to write the code, I realized there were several different ways to tackle the problem. For me this is a cool thing about Scala; it’s like the old Perl slogan, “There’s more than one way to do it.”
Without any further discussion, I’ll just say that the following Scala code demonstrates several different ways to generate a random string. I start with a “Java-esque” approach, and then show several other ways to create a random string, including some recursive and tail recursive approaches.
import scala.annotation.tailrec /** * Examples of different ways to write "random string" methods in Scala. * See the main method for examples of how each method is called. * Created by Alvin Alexander, http://alvinalexander.com */ object RandomStringExamples { def main(args: Array[String]) { println("1: " + randomString(10)) println("2: " + randomStringArray(10)) println("3: " + randomStringRecursive(10).mkString) println("3: " + randomStringRecursive2(10).mkString) println("4: " + randomStringTailRecursive(10, Nil).mkString) println("5: " + randomStringRecursive2Wrapper(10)) println("6: " + randomAlphaNumericString(10)) println("6: " + randomAlphaNumericString(10)) println("6: " + randomAlphaNumericString(10)) println("x2: " + x2(10, ('a' to 'z') ++ ('A' to 'Z'))) } // 1 - a 'normal' java-esque approach def randomString(length: Int) = { val r = new scala.util.Random val sb = new StringBuilder for (i <- 1 to length) { sb.append(r.nextPrintableChar) } sb.toString } // 2 - similar to #1, but using an array def randomStringArray(length: Int) = { val r = new scala.util.Random val a = new Array[Char](length) val sb = new StringBuilder for (i <- 0 to length-1) { a(i) = r.nextPrintableChar } a.mkString } // 3 - recursive, but not tail-recursive def randomStringRecursive(n: Int): List[Char] = { n match { case 1 => List(util.Random.nextPrintableChar) case _ => List(util.Random.nextPrintableChar) ++ randomStringRecursive(n-1) } } // 3b - recursive, but not tail-recursive def randomStringRecursive2(n: Int): String = { n match { case 1 => util.Random.nextPrintableChar.toString case _ => util.Random.nextPrintableChar.toString ++ randomStringRecursive2(n-1).toString } } // 4 - tail recursive, no wrapper @tailrec def randomStringTailRecursive(n: Int, list: List[Char]):List[Char] = { if (n == 1) util.Random.nextPrintableChar :: list else randomStringTailRecursive(n-1, util.Random.nextPrintableChar :: list) } // 5 - a wrapper around the tail-recursive approach def randomStringRecursive2Wrapper(n: Int): String = { randomStringTailRecursive(n, Nil).mkString } // 6 - random alphanumeric def randomAlphaNumericString(length: Int): String = { val chars = ('a' to 'z') ++ ('A' to 'Z') ++ ('0' to '9') randomStringFromCharList(length, chars) } // 7 - random alpha def randomAlpha(length: Int): String = { val chars = ('a' to 'z') ++ ('A' to 'Z') randomStringFromCharList(length, chars) } // used by #6 and #7 def randomStringFromCharList(length: Int, chars: Seq[Char]): String = { val sb = new StringBuilder for (i <- 1 to length) { val randomNum = util.Random.nextInt(chars.length) sb.append(chars(randomNum)) } sb.toString } def x(length: Int, chars: Seq[Char]): String = { val list = List.range(1, length) val arr = new Array[Char](length) list.foreach{ e => arr(e) = chars(util.Random.nextInt(chars.length)) } list.mkString } // create a fake list so i can use map (or flatMap) def x2(length: Int, chars: Seq[Char]): String = { val tmpList = List.range(0, length) val charList = tmpList.map{ e => chars(util.Random.nextInt(chars.length)) } return charList.mkString } }
I’m sure there are many other ways to generate a random string in Scala, but if nothing else, rather than solve a specific problem, I thought I’d just share all these different potential approaches.
Comments
Post a Comment