Standard function to enumerate all strings of given length over given alphabet - scala

Suppose, I have an alphabet of N symbols and want to enumerate all different strings of length M over this alphabet. Does Scala provide any standard library function for that?

Taking inspiration from another answer:
val letters = Seq("a", "b", "c")
val n = 3
Iterable.fill(n)(letters) reduceLeft { (a, b) =>
for(a<-a;b<-b) yield a+b
}
Seq[java.lang.String] = List(aaa, aab, aac, aba, abb, abc, aca, acb, acc, baa, bab, bac, bba, bbb, bbc, bca, bcb, bcc, caa, cab, cac, cba, cbb, cbc, cca, ccb, ccc)
To work with something other than strings:
val letters = Seq(1, 2, 3)
Iterable.fill(n)(letters).foldLeft(List(List[Int]())) { (a, b) =>
for (a<-a;b<-b) yield(b::a)
}
The need for the extra type annotation is a little annoying but it will not work without it (unless someone knows another way).

Another solution:
val alph = List("a", "b", "c")
val n = 3
alph.flatMap(List.fill(alph.size)(_))
.combinations(n)
.flatMap(_.permutations).toList
Update: If you want to get a list of strings in the output, then alph should be a string.
val alph = "abcd"

Related

group list elements if they share a common element

I have a list of strings. The elements are comprised of two letters. For Example,
val A = List("bf", "dc", "ab", "af")
I want to collect all the letters that share a common letter, i.e.,
"bf" and "af" share "f"
into a tuple
("a", "b", "f")
the other tuple would be
("c", "d")
so I want to return a list that looks like this
List(List("a", "b", "f"), List("c", "d"))
I got my intended result with
val A= List("bf", "dc", "ab", "af")
val B= A.flatMap(x => x.split("")).distinct
B.map(y => A.map(x => if(x.contains(y)) {x} else {""}).filter(_ !="").flatMap(_.split("")).distinct.sorted).distinct
but there must be a better way.
Your solution is not bad, but can be simplified.
You don't have to split the strings and flatMap then. You can just flatten the List of Strings.
A.map(x => if(x.contains(y)) {x} else {""}).filter(_!="")
It would be better to write:
A.flatMap(x => if(x.contains(y)) Some(x) else None) or
A.filter(_.contains(y))
But you can use partition and count to express it, here is my solution:
val a = List("bf", "dc", "ab", "af")
val b = a.flatten.distinct.sorted
b.partition(x => a.count(_.contains(x)) > 1)
I am curious, "better" in what sense? If you care about algorithm complexity in terms of Big O, then assuming the following:
the alphabet is simple, let it be 26 letters;
the strings are of arbitrary length, but much smaller than the input's length n.
Then you can do it in O(n):
def fn(in: Iterator[String]) = {
val a = Array.fill(26)(-1)
for {s <- in} {
val cl = s.toSeq.map(_ - 'a')
val i = cl.map(a(_)).find(_ >= 0) getOrElse cl.head
cl.foreach(a(_) = i)
}
a.zipWithIndex.filter(_._1 > 0).groupBy(_._1).values.map {
_.map(_._2+'a').map(_.toChar)
}
}
scala> fn(List("bf", "dc", "ab", "af").toIterator)
res17: Iterable[Array[Char]] = List(Array(a, b, f), Array(c, d))
Back to "better". If you wanted a nifty FP solution, then some may say that we sacrifice FP here, because used a mutable variable.
It's arguable, since that mutable variable is scoped inside and the function is still pure.

Merge Two Scala Lists of Same Length, With Elements At Same Index Becoming One Element

I have two Scala lists with the same number and type of elements, like so:
val x = List("a", "b", "c")
val y = List("1", "2", "3")
The result I want is as follows:
List("a1", "b2", "c3")
How can this be done in Scala? I could figure this out using mutable structures but I think that would be unidiomatic for Scala.
Combine zip and map:
x zip y map { case (a, b) => a + b }
Strangely enough, this also works:
x zip y map (_.productIterator.mkString)
but I would strongly prefer the first version.

how to delete the elements that have the same prefix String (2 to 5 Chars) in a List?

there is a List as below:
val a: List[String] = List(aaaaa1, aaaaa2, bb, cc, dd1, ee, dd2, dd3, ff, ggg1, ggg2, aaaaa3)
how to delete the elements that have the same prefix String (2 to 5 Chars) in a List?
for example:
"aaaaa1","aaaaa2","aaaaa3" have the same prefix String "aaaaa"(5 Chars). so delete them.
"dd1","dd2","dd3" have the same prefix String "dd"(2 Chars). so delete them.
"ggg1","ggg2" have the same prefix String "ggg"(3 Chars). so delete them.
expected:
val b: List[String] = List(bb,cc,ee,ff)
==========
thx for your idea. now fix it.
a.foldLeft(scala.collection.mutable.LinkedHashMap[String,Int]().withDefaultValue(0)){
case(m,e) =>
val k = e.take(2)
m(k)+=1
m
}.filter(_._2==1).keys.toList
Try this.
a.groupBy(_.take(2)).values.collect{case x if x.length == 1 => x.head}
// res0: Iterable[String] = List(cc, bb, ee, ff)
The original order is not retained because the collection passes through a Map() phase which, by definition, has no intrinsic order.
update
The original order can be preserved but it requires a two-step procedure.
val uniqPrefix = a.groupBy(_.take(2)).mapValues(_.length == 1)
a.filter(x => uniqPrefix(x.take(2)))
// res0: List[String] = List(bb, cc, ee, ff)
I think this code can be used in this case:
val list = List(
"aaaaa1", "aaaaa2", "bb", "cc", "dd1", "ee", "dd2", "dd3", "ff", "ggg1", "ggg2", "aaaaa3")
val prefix2items = list.groupBy(_.take(2))
list.filter(item => prefix2items(item.take(2)).length == 1)
//res0: List[String] = List(bb, cc, ee, ff)
This would work even if you have multiple character in prefix
The prefix will be identify until get a digit, the character after digit will not consider as prefix here
val a = List("abb1","abbbbbb1","aaaaa2","aaaaa3","aaaaaa44")
"abb1" will be removed here
a.filter(_.takeWhile(data => !data.isDigit).groupBy(_.toChar).values.exists{case x if (2 to 5).contains(x.length) => true case _ => false})

How to get combined lists from two list using scala?

I have two lists
val list1 = List((List("AAA"),"B1","C1"),(List("BBB"),"B2","C2"))
val list2 = List(("AAA",List("a","b","c")),("BBB",List("c","d","e")))
I want to match first element from list2 with first element of list1 and get combined list.
I want output as -
List((List("AAA"),"B1","C1",List("a","b","c")))
How to get above output using Scala??
This is what I came up with:
scala> val l1 = List((List("AAA"),"B1","C1"),(List("BBB"),"B2","C2"))
l1: List[(List[String], String, String)] = List((List(AAA),B1,C1), (List(BBB),B2,C2))
scala> val l2 = List((List("AAA"), List("a", "b", "c")), (List("BBB"), List("c", "d", "e")))
l2: List[(String, List[String])] = List((AAA,List(a, b, c)), (BBB,List(c, d, e)))
scala> l1.collectFirst {
| case tp => l2.find(tp2 => tp2._1.head == tp._1.head).map(founded => (tp._1, tp._2, tp._3, founded._2))
| }.flatten
res2: Option[(List[String], String, String, List[String])] = Some((List(AAA),B1,C1,List(a, b, c)))
You can use collectFirst to filter values you don't want and on every tuple you use find on the second list and map it into the tuple you want.
A couple of notes, this is horrible, I don't know how you got with a Tuple4 in the first place, I personally hate all that tp._* notation, it's hard to read, think about using case classes to wrap all that into some more manageable structure, second I had to use .head which in case of empty list will throw an exception so you may want to do some checking before that, but as I said, I would completely review my code and avoid spending time working on some flawed architecture in the first place.
You can use zip to combine both the list
val list1 = List((List("AAA"),"B1","C1"),(List("BBB"),"B2","C2"))
val list2 = List(("AAA",List("a","b","c")),("BBB",List("c","d","e")))
val combinedList = (list1 zip list2)
combinedList.head will give you the desired result
It will give the combined list from which you can get the first element

Map versus FlatMap on String

Listening to the Collections lecture from Functional Programming Principles in Scala, I saw this example:
scala> val s = "Hello World"
scala> s.flatMap(c => ("." + c)) // prepend each element with a period
res5: String = .H.e.l.l.o. .W.o.r.l.d
Then, I was curious why Mr. Odersky didn't use a map here. But, when I tried map, I got a different result than I expected.
scala> s.map(c => ("." + c))
res8: scala.collection.immutable.IndexedSeq[String] = Vector(.H, .e, .l, .l, .o,
". ", .W, .o, .r, .l,
I expected that above call to return a String, since I'm map-ing, i.e. applying a function to each item in the "sequence," and then returning a new "sequence."
However, I could perform a map rather than flatmap for a List[String]:
scala> val sList = s.toList
sList: List[Char] = List(H, e, l, l, o, , W, o, r, l, d)
scala> sList.map(c => "." + c)
res9: List[String] = List(.H, .e, .l, .l, .o, ". ", .W, .o, .r, .l, .d)
Why was a IndexedSeq[String] the return type of calling map on the String?
The reason for this behavior is that, in order to apply "map" to a String, Scala treats the string as a sequence of chars (IndexedSeq[String]). This is what you get as a result of the map invocation, where for each element of said sequence, the operation is applied. Since Scala treated the string as a sequence to apply map, that is what mapreturns.
flatMap then simply invokes flatten on that sequence afterwards, which then "converts" it back to a String
You also have an interesting "collection of Scala flatMap examples", the first of which illustrates that difference between flatMap and map:
scala> val fruits = Seq("apple", "banana", "orange")
fruits: Seq[java.lang.String] = List(apple, banana, orange)
scala> fruits.map(_.toUpperCase)
res0: Seq[java.lang.String] = List(APPLE, BANANA, ORANGE)
scala> fruits.flatMap(_.toUpperCase)
res1: Seq[Char] = List(A, P, P, L, E, B, A, N, A, N, A, O, R, A, N, G, E)
Quite a difference, right?
Because flatMap treats a String as a sequence of Char, it flattens the resulting list of strings into a sequence of characters (Seq[Char]).
flatMap is a combination of map and flatten, so it first runs map on the sequence, then runs flatten, giving the result shown.
You can see this by running map and then flatten yourself:
scala> val mapResult = fruits.map(_.toUpperCase)
mapResult: Seq[String] = List(APPLE, BANANA, ORANGE)
scala> val flattenResult = mapResult.flatten
flattenResult: Seq[Char] = List(A, P, P, L, E, B, A, N, A, N, A, O, R, A, N, G, E)
Your map function c => ("." + c) takes a char and returns a String. It's like taking a List and returning a List of Lists. flatMap flattens that back.
If you would return a char instead of a String you wouldn't need the result flattened, e.g. "abc".map(c => (c + 1).toChar) returns "bcd".
With map you are taking a list of characters and turning it into a list of strings. That's the result you see. A map never changes the length of a list – the list of strings has as many elements as the original string has characters.
With flatMap you are taking a list of characters and turning it into a list of strings and then you mush those strings together into a single string again. flatMap is useful when you want to turn one element in a list into multiple elements, without creating a list of lists. (This of course also means that the resulting list can have any length, including 0 – this is not possible with map unless you start out with the empty list.)
Use flatMap in situations where you run map followed by flattern. The specific situation is this:
• You’re using map (or a for/yield expression) to create a new collection from an existing collection.
• The resulting collection is a List of Lists.
• You call flatten immediately after map (or a for/yield expression).
When you’re in this situation, you can use flatMap instead.
Example: Add all the Integers from the bag
val bag = List("1", "2", "three", "4", "one hundred seventy five")
def toInt(in: String): Option[Int] = {
try {
Some(Integer.parseInt(in.trim))
} catch {
case e: Exception => None
}
}
Using a flatMap method
> bag.flatMap(toInt).sum
Using map method (3 steps needed)
bag.map(toInt) // List[Option[Int]] = List(Some(1), Some(2), None, Some(4), None)
bag.map(toInt).flatten //List[Int] = List(1, 2, 4)
bag.map(toInt).flatten.sum //Int = 7