How to pad a Scala collection for minimum size? - scala

How to make sure a Seq is of certain minimum length, in Scala?
The below code does what I want (adds empty strings until arr has three entries), but it feels clumsy.
scala> val arr = Seq("a")
arr: Seq[String] = List(a)
scala> arr ++ Seq.fill(3-arr.size)("")
res2: Seq[String] = List(a, "", "")
A way to fulfill this would be a merger of two sequences: take from first, but if it runs out, continue from second. What was such method called...?

I find this slightly better:
scala> (arr ++ Seq.fill(3)("")).take(3)
res4: Seq[String] = List(a, "", "")
And even better, thanks #thomas-böhm
scala> arr.toArray.padTo(3,"")
res5: Array[String] = Array(a, "", "")

arr.padTo(3,"")
It was too trivial.

Related

Define a 2d list and append lists to it in a for loop, scala

I want to define a 2d list before a for loop and afterwards I want to append to it 1d lists in a for loop, like so:
var 2dEmptyList: listOf<List<String>>
for (element<-elements){
///do some stuff
2dEmptyList.plusAssign(1dlist)
}
The code above does not work. But I can't seem to find a solution for this and it is so simple!
scala> val elements = List("a", "b", "c")
elements: List[String] = List(a, b, c)
scala> val twoDimenstionalList: List[List[String]] = List.empty[List[String]]
twoDimenstionalList: List[List[String]] = List()
scala> val res = for(element <- elements) yield twoDimenstionalList ::: List(element)
res: List[List[java.io.Serializable]] = List(List(a), List(b), List(c))
Better still:
scala> twoDimenstionalList ::: elements.map(List(_))
res8: List[List[String]] = List(List(a), List(b), List(c))
If you want 2dEmptyList be mutable, please consider using scala.collection.mutable.ListBuffer:
scala> val ll = scala.collection.mutable.ListBuffer.empty[List[String]]
ll: scala.collection.mutable.ListBuffer[List[String]] = ListBuffer()
scala> ll += List("Hello")
res7: ll.type = ListBuffer(List(Hello))
scala> ll += List("How", "are", "you?")
res8: ll.type = ListBuffer(List(Hello), List(How, are, you?))

Scala: Create a new list where each element is the elemnt of old list repeated with different suffix

This seems like it should be really easy but I can't quite put it together. I want to take a list of strings and create a new list that contains two of each element form the first list but with a different suffix. So:
List("a", "b", "c") -> List("a_x", "a_y", "b_x", "b_y", "c_x", "c_y"
I tried
val list2 = list1.map(i=> i+"_x", i+"_y")
but scala said I had too many arguments. This got close:
val list2 = list1.map(i=> (i+"_x", i+"_y"))
but it produced List(("a_x", "a_y"), ("b_x", "b_y"), ("c_x", "c_y")) which is not what I want. I'm sure I ;m missing something obvious.
You want flatMap, to first map, then flatten the structure of the result into a flat list. Each individual result must itself be a collection (not a tuple):
scala> List("a", "b", "c").flatMap(i => List(i + "-x", i + "-y"))
res0: List[String] = List(a-x, a-y, b-x, b-y, c-x, c-y)
With a for comprehension:
scala> val prefixes = List("a", "b", "c")
prefixes: List[String] = List(a, b, c)
scala> val suffixes = List("x", "y")
suffixes: List[String] = List(x, y)
scala> for (prefix <- prefixes; suffix <- suffixes) yield prefix + "_" + suffix
res1: List[String] = List(a_x, a_y, b_x, b_y, c_x, c_y)
This is basically just syntactic sugar for Seth Tisue's answer.

Trying to append to Iterable[String]

I'm trying to add another string to Iterable[String] for easy concatenation, but the result is not what I expect.
scala> val s: Iterable[String] = "one string" :: "two string" :: Nil
s: Iterable[String] = List(one string, two string)
scala> s.mkString(";\n")
res3: String =
one string;
two string
scala> (s ++ "three").mkString(";\n")
res5: String =
one string;
two string;
t;
h;
r;
e;
e
How should I should I rewrite this snippet to have 3 string in my iterable?
Edit: I should add, that order of items should be preserved
++ is for collection aggregation. There is no method +, :+ or add in Iterable, but you can use method ++ like this:
scala> (s ++ Seq("three")).mkString(";\n")
res3: String =
one string;
two string;
three
The ++ function is waiting for a Traversable argument. If you use just "three", it will convert the String "three" to a list of characters and append every character to s. That's why you get this result.
Instead, you can wrap "three" in an Iterable and the concatenation should work correctly :
scala> (s ++ Iterable[String]("three")).mkString(";\n")
res6: String =
one string;
two string;
three
I like to use toBuffer and then +=
scala> val l : Iterable[Int] = List(1,2,3)
l: Iterable[Int] = List(1, 2, 3)
scala> val e : Iterable[Int] = l.toBuffer += 4
e: Iterable[Int] = ArrayBuffer(1, 2, 3, 4)
or in your example:
scala> (s.toBuffer += "three").mkString("\n")
I have no idea why this operation isn't supported in the standard library. You can also use toArray but if you add more than one element this will be less performant - I would assume - as the buffer should return itself if it another element is added.

How do I convert an Array[String] to a Set[String]?

I have an array of strings. What's the best way to turn it into an immutable set of strings?
I presume this is a single method call, but I can't find it in the scala docs.
I'm using scala 2.8.1.
This method called toSet, e.g.:
scala> val arr = Array("a", "b", "c")
arr: Array[java.lang.String] = Array(a, b, c)
scala> arr.toSet
res1: scala.collection.immutable.Set[java.lang.String] = Set(a, b, c)
In this case toSet method does not exist for the Array. But there is an implicit conversion to ArrayOps.
In such cases I can advise you to look in Predef. Normally you should find some suitable implicit conversion there. genericArrayOps would be used in this case. genericWrapArray also can be used, but it has lower priority.
scala> val a = Array("a", "b", "c")
a: Array[java.lang.String] = Array(a, b, c)
scala> Set(a: _*)
res0: scala.collection.immutable.Set[java.lang.String] = Set(a, b, c)
// OR
scala> a.toSet
res1: scala.collection.immutable.Set[java.lang.String] = Set(a, b, c)

What's the best way to create a dynamically growing array in Scala?

I wanted to add items dynamically into an array. But it seems Scala arrays and lists don't provide any methods for adding items dynamically due to the immutable nature.
So I decided to use List data type to make use of this :: method to achieve this. My code look like this
var outList = List(Nil)
val strArray = Array("ram","sam","bam")
for (str<-strArray)
outList = str :: outList
Though it works in some way, the problem is the new strings are pre-appended into the list. But the ideal requirement is order of the data. Yeah, I know what you are thinking, you can reverse the final result list to get the original order. But the problem is it's a huge array. And I believe it's not a solution though it solves the problem. I believe there should be a simple way to solve this...
And my reason for hacking Scala is to learn the functional way of coding. Having var (mutable type) and populating the list on the fly seems to me is not a functional way of solving things.
How can I do it?
Ideally, I want to achieve something like this in Scala (below the C# code)
List<int> ls = new List<int>();
for (int i = 0; i < 100; i++)
ls.Add(i);
But it seems Scala Arrays & Lists doesn't provide any methods for adding items dynamically due to the immutable nature.
Well, no. Scala Arrays are just Java arrays, so they are mutable:
val arr = Array(1,2)
arr(0) = 3 // arr == Array(3, 2)
But just as Java (and C/C++/C#/etc.) arrays, you can't change the size of an array.
So you need another collection, which is backed by an array, but does allow resizing. A suitable collection in Scala is scala.collection.mutable.ArrayBuffer, java.util.ArrayList in Java, etc.
If you want to get a List instead of an Array in the end, use scala.collection.mutable.ListBuffer instead.
Going after retronym's answer:
If you still want to use list there are a few ways to prepend an item to the list. What you can do is (yes the top part is still wrong):
scala> var outList : List[String] = Nil
outList: List[String] = List()
scala> val strArray = Array("a","b","c")
strArray: Array[java.lang.String] = Array(a, b, c)
scala> for(s <- strArray)
| outList = outList :+ s
scala> outList
res2: List[String] = List(a, b, c)
Note the :+ operator. If you rather append, you'd use s +: outList.
Now who says programming in Scala isn't fun? ;)
P.S. Maybe the reason why you'd want to make them immutable is the speed. Handling large data will be more efficient with immutable data types. Am I right?
If you want to use a mutable Buffer, as retronym mentioned. It looks like this:
scala> var outList = scala.collection.mutable.Buffer[String]()
outList: scala.collection.mutable.Buffer[String] = ArrayBuffer()
scala> for(str<-strArray) outList += str
scala> outList
res10: scala.collection.mutable.ListBuffer[String] = ListBuffer(ram, sam, bam)
Anyway, perhaps it is better to directly do the things you want to do with the strArray. E.g:
strArray map(_.toUpperCase) foreach(println)
If you want to work with immutable structures, you can use the ++ method:
scala> val orgList = List(1,2,3)
orgList: List[Int] = List(1, 2, 3)
scala> val list2Add = List(4,5,6)
list2Add: List[Int] = List(4, 5, 6)
scala> val newList = orgList ++ list2Add
newList: List[Int] = List(1, 2, 3, 4, 5, 6)
If you want to do more work on the elements than just adding them you can use higher order functions:
val newList = orgList ++ list2Add.map(_ * 2)
newList: List[Int] = List(1, 2, 3, 8, 10, 12)
Or with a for loop:
val newList = orgList ++ {for(x <- list2Add) yield 2*x}
Or you could create some recursive loop:
def addAll(toList: List[Int], fromList: List[Int]): List[Int] =
fromList match {
case x :: tail => addAll(2*x :: toList, tail)
case Nil => toList
}
val newList = addAll(orgList, list2Add )
but in this case the ordering of the added elements will be in reversed:
List(12, 10, 8, 1, 2, 3)
If you want performance when working with lists, it is better to reverse the result than try to add new elements in the end. Adding elements in the end to a list is nooot good :-)
Okay, there are a few things to clear up.
This is wrong, you're make a one element list, containing an empty list:
scala> var outList = List(Nil)
outList: List[object Nil] = List(List())
Nil is the empty list:
scala> var outList: List[String] = Nil
outList: List[String] = List()
Or, if you prefer:
scala> var outList = List[String]()
outList: List[String] = List()
Without more context, it's hard to know what you mean by 'dynamically'. Your example code would be better written as:
scala> val strArray = Array("ram","sam","bam")
strArray: Array[java.lang.String] = Array(ram, sam, bam)
scala> strArray toList
res0: List[java.lang.String] = List(ram, sam, bam)
If you want a mutable collection that can grow and efficiently handle prepend, append, and insert operations, you could use scala.mutable.Buffer.
If you are looking to create a new collection, you can use the yield key word:
val outlist = for(i <- 0 to 100) yield i
Or:
val arrList = "Some" :: "Input" :: "List" :: Nil
val outlist = for ( i <- arrList ) yield i
Technically, outlist is a Seq in both of the above examples so you may need to call the toList method on it if you need some of List's methods.
We can use ArrayBuffer as suggested.
However, i have created a simple program which takes no of parameters for an Array of int and it will let you enter the numbers and finally we are displaying them.
val arraySize = scala.io.StdIn.readLine().toInt
val arr = new ArrayBuffer[Int]() ++ (1 to arraySize).map{
i =>
scala.io.StdIn.readLine().toInt
}
println(arr.mkString(","))