group list elements if they share a common element - scala

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.

Related

Subsequence in a sequence of numbers in scala

For example i have:
List(1,3,2,5)
How i get all these:
List(1), List(3), List(2), List(5), List(1,3), List(1,2), List(1,5), List(3,2), List(3,5), List(2,5), List(1,3,2), List(1,3,5), List(1,2,5), List(3,2,5), List(1,3,2,5))
I need this for Longest Increasing Subsequence -problem and this answer for example would be: (1,3,5)
And I want use it for bigger Lists.
You want all the combinations() from 1 to array length.
val arr = Array(4, 3, 1)
arr.indices.flatMap(x => arr.combinations(x + 1))
//res0: Seq[Array[Int]] = Vector(Array(4), Array(3), Array(1), Array(4, 3), Array(4, 1), Array(3, 1), Array(4, 3, 1))
update
This will give you all possible combinations, retaining original order and duplicate elements.
def subseqs[A](seq :Seq[A]) :List[Seq[A]] = seq match {
case hd +: tl =>
val res = subseqs(tl)
Seq(hd) :: res ++ res.map(hd +: _)
case Seq() => Nil
}
The result is a List of n^2 - 1 possible sub-sequences. So for a collection of 8 elements you'll get 255 sub-sequences.
This, of course, is going to be way too tedious and inefficient for your purposes. Generating all possible sub-sequences in order to find the Longest Increasing is a little like washing all the clothes in your neighborhood so you'll have clean socks in the morning.
Much better to generate only the increasing sub-sequences and find the longest from that set (9 lines of code).
[ Update in response to updated question ]
[ Thanks to #jwvh for spotting error in original version ]
This method will generate all possible sub-sequences of a List:
def subsequences[T](list: List[T]): List[List[T]] =
list match {
case Nil =>
List(List())
case hd :: tl =>
val subs = subsequences(tl)
subs.map(hd +: _) ++ subs
}
Note that this is not efficient for a number of reasons, so it is not a good way to solve the "longest increasing subsequence problem".
[ Original answer ]
This function will generate all the non-empty contiguous sub-sequences of any sequence:
def subsequences[T](seq: Seq[T]) =
seq.tails.flatMap(_.inits).filter(_.nonEmpty)
This returns an Iterator so it creates each sub-sequence in turn which reduces memory usage.
Note that this will generate all the sub-sequences and will preserve the order of the values, unlike solutions using combinations or Set.
You can use this in your "longest increasing subsequence problem" like this:
def isAscending(seq: Seq[Int]): Boolean =
seq.length <= 1 || seq.sliding(2).forall(x => x(0) < x(1))
subsequences(a).filter(isAscending).maxBy(_.length)
The result will be the longest sequence of ascending values in the input a.

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 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

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

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"

Get index of current element in a foreach method of Traversable?

Suppose I have two arrays:
val ar1 = Array[String]("1", "2", "3")
val ar2 = Array[String]("1", "2", "3", "4")
Now for each element of ar1, I want to first concatenate that element with the corresponding element of ar2, and then print the result. One way to do would be something like:
List.range(0, ar1.size).foreach(i => println(ar1(i)+ar2(i)))
It would have been nicer if there was a foreach variant that would allow me to work directly with the indices of ar1 instead of first constructing the integer list.
Perhaps there is a better way?
One very convenient way to do this is with the zipped method on tuples. Put two collections in, get out two arguments to a function!
(ar1,ar2).zipped.foreach((x,y) => println(x+y))
This is both convenient to write and fast, since you don't need to build a tuple to store each pair (as you would with (ar1 zip ar2)) which you then have to take apart again. Both forms of zip stop when the shorter of the two collections is exhausted.
If you have something more complicated (e.g. you need to do math on the index), the canonical solution is to zip in the index:
ar1.zipWithIndex.foreach{ case(x,i) => println(x+ar2(i)) }
The method you are using is more rapidly and compactly done as follows, an can be useful:
ar1.indices.foreach(i => println(ar1(i)+ar2(i)))
although this only works if the first collection is no longer than the second. You can also specify your ranges explcitly:
(0 until (ar1.size min ar2.size)).foreach(i => println(ar1(i)+ar2(i)))
to get around this problem. (You can see why zip and zipped are preferred unless what you're doing is too complicated for this to work easily.)
If it is not a parallel collection (and usually it is not unless you call .par), it's also possible, though not recommended, to keep track with a mutable variable:
{ var i=-1; ar1.foreach{ x => i += 1; println(x+ar2(i)) } }
There are a very limited number of cases where this is necessary (e.g. if you may want to skip or backtrack on some of the other collection(s)); if you can avoid having to do this, you'll usually end up with code that's easier to reason about.
This is how you loop with an index in idiomatic Scala:
scala> List("A", "B", "C").zipWithIndex foreach { case(el, i) =>
| println(i + ": " + el)
| }
0: A
1: B
2: C
And here is the idiomatic Scala way to do what you are trying to achieve in your code:
scala> val arr1 = Array("1", "2", "3")
arr1: Array[java.lang.String] = Array(1, 2, 3)
scala> val arr2 = Array("1", "2", "3", "4")
arr2: Array[java.lang.String] = Array(1, 2, 3, 4)
scala> (arr1, arr2).zipped.map(_ + _) foreach println
11
22
33
I did not had the opportunity to test it, but this should do the trick:
ar1.zip(ar2).foreach(x => println(x._1 + x._2))
zip will do it:
ar1 zip ar2 foreach { p => println(p._1 + p._2) }
This will yield:
11
22
33
Note that you don't need [String] generic type, will be infered by the compiler:
val ar1 = Array("1", "2", "3")
val ar2 = Array("1", "2", "3", "4")