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)
Related
I’m doing Ruby task, which is “You have an array of numbers. Your task is to sort ascending odd numbers but even numbers must be on their places. Zero isn't an odd number and you don't need to move it. If you have an empty array, you need to return it”.
Decided to split initial array: odd nums pushed into another array, sorted it and even numbers added to hash, where the key is num and its initial index is value. After that, trying to insert the even nums from hash to odd array, at initial indexes of even nums. So, the code looks like this:
def sort_array(source_array)
even_nums = Hash.new
odd_nums = []
return source_array if source_array.length == 0
source_array.each_with_index {|n, ind| even_nums[n] = ind if n.even?}
source_array.select{|n| odd_nums.push(n) if n.odd?}
odd_nums.sort!
even_nums.each do |k, v|
odd_nums.insert(v, k)
end
odd_nums
end
With small array like [5, 3, 2, 8, 1, 4, 11] it works as expected but if I pass something bigger like [84, -64, 40, 53, 5, 88, 2, 14, 29, -79, -44, -23, 20, -67, -12, 28, -28, -37, -27, -62, -54, 93, -61, 50, 65, -63, -62, 77, -16, 49, -43, 26, -73, -27, 88, -88, -62, 84, 54, 25, 25, -2, -99, 69, -23, 47, -92, 7, -62, -62, -58, -30, -75, -31, 65, -63, 16, 64, -7, -22, -6, -82]
I’m getting nils at the end of the sorted array. Like this:
[-99, -64, 40, -79, -75, -73, 2, 14, -67, -63, -44, -63, 20, -61, -12, 28, -28, -43, -37, -31, -54, -27, -27, 50, -23, -23, -7, 5, -16, 7, 25, 26, 25, 29, 47, -88, 49, 53, 54, 65, 65, -2, 69, 77, 93, nil, -92, nil, nil, 88, -58, -30, nil, nil, nil, nil, 16, 64, nil, -22, -6, -82, 84, nil, -62]
Struggling to understand, why it isn’t working with bigger arrays?
There's a fairly easy way to do this if you think about it as two operations:
def sort_array(arr)
# Extract and sort the odd values
odd = arr.select(&:odd?).sort
# Merge the sorted odd values back in
arr.map do |v|
v.odd? ? odd.shift : v
end
end
Not much to it.
You had some of the right pieces, but I think you got stuck in the weeds when it started to get overly complicated.
That can be done as follows.
def sort_odds(arr)
odd_pos = arr.each_index.select { |i| arr[i].odd? }
odd_pos.zip(odd_pos.sort_by { |i| arr[i] }).
each_with_object(arr.dup) do |(old_pos,new_pos),a|
a[new_pos] = arr[old_pos]
end
end
sort_odds [5, 3, 2, 8, 1, 4, 11]
# o o e e o e o
#=> [1, 3, 2, 8, 5, 4, 11]
The steps are as follows.
arr = [5, 3, 2, 8, 1, 4, 11]
# o o e e o e o
odd_pos = arr.each_index.select { |i| arr[i].odd? }
#=> [0, 1, 4, 6]
new_pos = odd_pos.zip(odd_pos.sort_by { |i| arr[i] })
#=> [[0, 4], [1, 1], [4, 0], [6, 6]]
new_pos.each_with_object(arr.dup) do|(old_pos,new_pos),a|
a[new_pos] = arr[old_pos]
end
#=> [1, 3, 2, 8, 5, 4, 11]
I think this other answer is simpler and more elegant than mine, but this works too. Notably, this solution would allow you to validate the position of your even numbers (for example, in a spec) by looking up the indexes and values in evens. Unless you already know what the output array should look like, this may matter when it comes time to debug the interim results.
def odd_sorted array
odds = array.select { |e| e.odd? }.sort
evens = array.each_with_index.select { |e| e.first.even? }
arr2 = Array.new(array.size)
# put even numbers in at their previous index
evens.each do |e|
arr2.each_index { |i| arr2[i] = e[0] if e[1] == i }
end
arr2.each_with_index { |e, i| arr2[i] = odds.shift if e.nil? }
end
odd_sorted [5, 3, 2, 8, 1, 4, 11]
#=> [1, 3, 2, 8, 5, 4, 11]
odd_sorted [84, -64, 40, 53, 5, 88, 2, 14, 29, -79, -44, -23, 20]
#=> [84, -64, 40, -79, -23, 88, 2, 14, 5, 29, -44, 53, 20]
The Array#map solution is definitely more elegant, but this is (in my personal opinion) more debuggable. Your mileage in that regard will certainly vary.
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)
Given Scala arrayBuffer:
ArrayBuffer(200, 13, 1, 200, 15, 1, 201, 13, 0, 202, 14, 3, 199, 10, 2, 199, 11, 3, 199, 96, 2)
Expected output:
ArrayBuffer((200, 13, 1), (200, 15, 1), (201, 13, 0), (202, 14, 3), (199, 10, 2), (199, 11, 3), (199, 96, 2))
Is there any simple way of achieving this form of chunking in Scala without for loops? The required chunk_size is 3. And the order of these elements must be the same.
I've tried:
def chunkArray(myArray){
val chunk_size = 3
var index = 0
var arrayLength = arrayToInsert.length
var tempArray = ArrayBuffer[Int](2)
val numChunks = arrayToInsert.length / 3
for (i <- 0 to numChunks-1) {
var myChunk = arrayToInsert.slice(i*chunk_size, (i+1)*chunk_size)
tempArray += (myChunk(0), myChunk(1), myChunk(2))
}
}
Expected result:
((200, 13, 1), (200, 15, 1), (201, 13, 0), (202, 14, 3), (199, 10, 2), (199, 11, 3), (199, 96, 2))
You want to use .grouped(3)
( the collections API examples )
collection.mutable.ArrayBuffer(200, 13, 1, 200, 15, 1, 201, 13, 0, 202, 14, 3, 199, 10, 2, 199, 11, 3, 199, 96, 2).grouped(3).toArray
res2: Array[collection.mutable.ArrayBuffer[Int]] = Array(ArrayBuffer(200, 13, 1), ArrayBuffer(200, 15, 1), ArrayBuffer(201, 13, 0), ArrayBuffer(202, 14, 3), ArrayBuffer(199, 10, 2), ArrayBuffer(199, 11, 3), ArrayBuffer(199, 96, 2))
This will create a Buffer of tuples, which is what the original code appears to attempt.
import collection.mutable.ArrayBuffer
val data =
ArrayBuffer(200, 13, 1, 200, 15, 1, 201, 13, 0 /*etc.*/)
data.grouped(3).collect{case Seq(a,b,c) => (a,b,c)}.toBuffer
//res0: Buffer[(Int, Int, Int)] = ArrayBuffer((200,13,1), (200,15,1), (201,13,0) /*etc.*/)
Note that if the final group is not 3 elements then it will be ignored.
This could also be achieved using sliding:
myArray.sliding(3, 3).toArray
Anyway, .grouped is better suited for this use case as discussed here Scala: sliding(N,N) vs grouped(N)
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)
I have a string of digits:
s = "12345678910"
As you can see it is the numbers 1 through 10 listed in increasing order. I want to convert it to an array of those numbers:
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
How can I do it?
How about this:
a = ["123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899"]
b = a.first.each_char.map {|n| n.to_i }
if b.size > 8
c = b[0..8]
c += b[9..b.size].each_slice(2).map(&:join).map(&:to_i)
end
# It would yield as follows:
[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]
For later numbers beyond 99, modify existing predicate accordingly.
Assuming a monotonic sequence, here's my run at it.
input = a.first.chars
output = []
previous_int = 0
until input.empty?
temp = []
temp << input.shift until temp.join.to_i > previous_int
previous_int = temp.join.to_i
output << previous_int
end
puts output.to_s
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Assumptions
the first (natural) number extracted from the string is the first character of the string converted to an integer;
if the number n is extracted from the string, the next number extracted, m, satisfies n <= m (i.e., the sequence is monotonically non-decreasing);
if n is extracted from the string, the next number extracted will have as few digits as possible (i.e., at most one greater than the number of digits in n); and
there is no need to check the validity of the string (e.g., "54632" is invalid).
Code
def split_it(str)
return [] if str.empty?
a = [str[0]]
offset = 1
while offset < str.size
sz = a.last.size
sz +=1 if str[offset,sz] < a.last
a << str[offset, sz]
offset += sz
end
a.map(&:to_i)
end
Examples
split_it("12345678910")
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
split_it("12343636412252891407189118901")
#=> [1, 2, 3, 4, 36, 36, 41, 225, 289, 1407, 1891, 18901]