How can I split a list of tuples scala - scala

I have this list in Scala (which in reality has length 500):
List((1,List(1,2,3)), (2,List(1,2,3)), (3, List(1,2,3)))
What could I do so that I can make a new list which contains the following:
List((1,1), (1,2), (1,3), (2,1), (2,2), (2,3), (3,1), (3,2), (3,3))
Basically I wanna have a new list of tuples which will contain the first element of the old tuple and each element of the list inside the tuple. I am not sure how to start implementing this and this is why I have posted no code to show my attempt. I am really sorry, but I cant grasp this. I appreciate any help you can provide.

Exactly the same as #Andriy but using a for comprehension.
Which in the end is exactly the same but is more readable IMHO.
val result = for {
(x, ys) <- xs
y <- ys
} yield (x, y) // You can also use x -> y
(Again, I would recommend you to follow any tutorial, this is a basic exercise which if you had understand how map & flatMap works you shouldn't have any problem)

scala> val xs = List((1,List(1,2,3)), (2,List(1,2,3)), (3, List(1,2,3)))
xs: List[(Int, List[Int])] = List((1,List(1, 2, 3)), (2,List(1, 2, 3)), (3,List(1, 2, 3)))
scala> xs.flatMap { case (x, ys) => ys.map(y => (x, y)) }
res0: List[(Int, Int)] = List((1,1), (1,2), (1,3), (2,1), (2,2), (2,3), (3,1), (3,2), (3,3))

It's probably worth mentioning that the solution by Andriy Plokhotnyuk can also be re-written as a for-comprehension:
val list = List((1,List(1,2,3)), (2,List(1,2,3)), (3, List(1,2,3)))
val pairs = for {
(n, nestedList) <- list
m <- nestedList
} yield (n, m)
assert(pairs == List((1,1), (1,2), (1,3), (2,1), (2,2), (2,3), (3,1), (3,2), (3,3)))
The compiler will effectively re-write the for-comprehension to a flatMap/map chain as described in another answer.

Related

How the get the index of the duplicate pair in the scala list

I have a scala list like this below:
slist = List("a","b","c","a","d","c","a")
I want to get the index of the same element pair in this list.
For example,the result of this slist is
(0,3),(0,6),(3,6),(2,5)
which (0,3) means the slist(0)==slist(3)
(0,6) means the slist(0)==slist(6)
and so on.
So is there any method to do this in scala?
Thanks very much
There's simpler approaches but starting with zipWithIndex leads down this path. zipWithIndex returns a Tuple2 with the index and one of the letters. From there we groupBy the letter to get a map of the letter to it's indices and filter the ones with more than one value. Lastly, we have this MapLike.DefaultValuesIterable(List((a,0), (a,3), (a,6)), List((c,2), (c,5)))
which we take the indices from and make combinations.
scala> slist.zipWithIndex.groupBy(zipped => zipped._1).filter(t => t._2.size > 1).values.flatMap(xs => xs.map(t => t._2).combinations(2))
res40: Iterable[List[Int]] = List(List(0, 3), List(0, 6), List(3, 6), List(2, 5))
Indexing a List is rather inefficient so I recommend a transition to Vector and then back again (if needed).
val svec = slist.toVector
svec.indices
.map(x => (x,svec.indexOf(svec(x),x+1)))
.filter(_._2 > 0)
.toList
//res0: List[(Int, Int)] = List((0,3), (2,5), (3,6))
val v = slist.toVector; val s = v.size
for(i<-0 to s-1;j<-0 to s-1;if(i<j && v(i)==v(j))) yield (i,j)
In Scala REPL:
scala> for(i<-0 to s-1;j<-0 to s-1;if(i<j && v(i)==v(j))) yield (i,j)
res34: scala.collection.immutable.IndexedSeq[(Int, Int)] = Vector((0,3), (0,6), (2,5), (3,6))

How to access second element in a Sequence in scala

val k = Seq((0,1),(1,2),(2,3),(3,4))
k: Seq[(Int, Int)] = List((0,1), (1,2), (2,3), (3,4))
If I have above statement and I need to do addition for even places and subtraction for odd places how can I access them? to be clear
(0,1) has to become (0,(1+2))
(1,2) has to become (1,(1-2))
(2,3) has to become (2,(3+4))
(3,4) has to become (3,(3-4)
Do you mean something like this?
val transformed = k.grouped(2).flatMap{
case Seq((i, x), (j, y)) => Seq((i, x + y), (j, x - y))
}
transformed.toList
// List[(Int, Int)] = List((0,3), (1,-1), (2,7), (3,-1))

For multiple generators to handle Seq

I'm a new to scala, and I want to unique a Seq[(Int,Int)] by the first component, my code as follow:
val seq = Seq((1,1), (0,1), (2,1), (0, 1), (3,1), (2,1))
val prev = -1
val uniqueSeq = for(tuple <- seq.sortBy(_._1) if !tuple._1.equals(prev); prev = tuple._1) yield tuple
but why the result is
uniqueSeq: Seq[(Int, Int)] = List((0,1), (0,1), (1,1), (2,1), (2,1), (3,1))
I would take a different approach:
It is a good idea to group them first. Then you can get the head of each of the groups:
seq.groupBy{
case (x, _) => x
}.map {
case (_, head :: _) => head
}.toList
prev in prev = tuple._1 is a completely different variable from val prev = -1! Note that it compiles even though the first prev is val, i.e. immutable (it can't be changed).
If you want to use this approach, you can:
val seq = Seq((1,1), (0,1), (2,1), (0, 1), (3,1), (2,1))
var prev = -1
val uniqueSeq = for(tuple <- seq.sortBy(_._1) if !tuple._1.equals(prev)) yield { prev = tuple._1; tuple }
but it isn't the idiomatic one in Scala. I'll leave that to someone else, since I don't have enough time right now.
Alexey already explained the mistake you're making with the prev variable.
A more idiomatic implementation of what you're trying to do (if I got it right) is
val seq = Seq((1,1), (0,1), (2,1), (0, 1), (3,1), (2,1))
seq.sortBy(_._1).reverse.toMap.toList // List((0,1), (1,1), (2,1), (3,1))
The caveat is that going through a Map the duplicate keys will disappear.
The reverse is necessary, since the last occurrence of a "key" will be preserved in the Map.

Scala generate unique pairs from list

Input :
val list = List(1, 2, 3, 4)
Desired output :
Iterator((1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4))
This code works :
for (cur1 <- 0 until list.size; cur2 <- (cur1 + 1) until list.size)
yield (list(cur1), list(cur2))
but it not seems optimal, is there any better way of doing it ?
There's a .combinations method built-in:
scala> List(1,2,3,4).combinations(2).toList
res0: List[List[Int]] = List(List(1, 2), List(1, 3), List(1, 4), List(2, 3), List(2, 4), List(3, 4))
It returns an Iterator, but I added .toList just for the purpose of printing the result. If you want your results in tuple form, you can do:
scala> List(1,2,3,4).combinations(2).map{ case Seq(x, y) => (x, y) }.toList
res1: List[(Int, Int)] = List((1,2), (1,3), (1,4), (2,3), (2,4), (3,4))
You mentioned uniqueness as well, so you could apply .distinct to your input list uniqueness isn't a precondition of your function, because .combination will not deduplicate for you.
.combinations is the proper way for generating unique arbitrary groups of any size, another alternative solution that does not check the uniqueness in first place is using foldLeft that way:
val list = (1 to 10).toList
val header :: tail = list
tail.foldLeft((header, tail, List.empty[(Int, Int)])) {
case ((header, tail, res), elem) =>
(elem, tail.drop(1), res ++ tail.map(x => (header, x)))
}._3
Will produce:
res0: List[(Int, Int)] = List((1,2), (1,3), (1,4), (1,5), (1,6), (1,7), (1,8), (1,9), (1,10), (2,3), (2,4), (2,5), (2,6), (2,7), (2,8), (2,9), (2,10), (3,4), (3,5), (3,6), (3,7), (3,8), (3,9), (3,10), (4,5), (4,6), (4,7), (4,8), (4,9), (4,10), (5,6), (5,7), (5,8), (5,9), (5,10), (6,7), (6,8), (6,9), (6,10), (7,8), (7,9), (7,10), (8,9), (8,10), (9,10))
If you expect there to be duplicates then you can turn the output list into a set and bring it back into a list, but you will lose the ordering then. Thus not the recommended way if you want to have uniqueness, but should be preferred if you want to generate all of the pairs included equal elements.
E.g. I used it in the field of machine learning for generating all of the products between each pair of variables in the feature space and if two or more variables have the same value I still want to produce a new variable corresponding to their product even though those newly generated "interaction variables" will have duplicates.

For comprehension with Map lookup - is there a better way?

Consider the following
val myMap: Map[String, List[Int]] = Map("a" -> List(1,2,3),
"b" -> List(4,5,6),
"d" -> List(7))
val possibleKeys: List[String] = List("c","a", "b", "e")
I would like to traverse the possible keys, and if the map contains one, traverse the map's values
The options I came up with are:
With a filter
for {
key <- possibleKeys
if (myMap contains key)
int <- myMap(key)
r <- 0 to int
} yield (r, int)
With getOrElse
for {
key <- possibleKeys
int <- myMap.getOrElse(key, Nil)
r <- 0 to int
} yield (r, int)
(Both return the same result:)
List((0,1), (1,1), (0,2), (1,2), (2,2), (0,3), (1,3), (2,3), (3,3), (0,4), (1,4), (2,4), (3,4), (4,4), (0,5), (1,5), (2,5), (3,5), (4,5), (5,5), (0,6), (1,6), (2,6), (3,6), (4,6), (5,6), (6,6))
Since I know Scala supports Options in for comprehensions, I was a bit surprised that this didn't work
for {
key <- possibleKeys
int <- myMap.get(key)
r <- 0 to int //<-- compilation error
} yield (r, int)
It complains about type mismatch; found : List[Int] required: Int
Which I vaguely understand why, but is there a way to make this work without the if clause or the getOrElse methods? (e.g. is there a way to get the myMap.get(key) version to work?)
You are trying to mix incompatible types in your for comprehension. You can fix it by converting the option to a Seq by example.
for {
key <- possibleKeys
ints <- myMap.get(key).toSeq
int <- ints
r <- 0 to int
} yield (r, int)
There is a rather nice explanation of the problem in this very similar question here: Type Mismatch on Scala For Comprehension.
You can make use of the methods keySet and apply on Map
for {
key <- possibleKeys
if myMap.keySet(key)
int <- myMap(key)
r <- 0 to int
} yield (r, int)
res5: List[(Int, Int)] = List((0,1), (1,1), (0,2), (1,2), (2,2), (0,3), (1,3), (2,3), (3,3), (0,4), (1,4), (2,4), (3,4), (4,4), (0,5), (1,5), (2,5), (3,5), (4,5), (5,5), (0,6), (1,6), (2,6), (3,6), (4,6), (5,6), (6,6))