I just started playing with scala and i cross the following issue. I want to simply return a Map with Int as key and List of Tuples for values. That is my method:
def findOpenTiles(board: Array[Array[Int]]): Map[Int, List[(Int, Int)]]={
val openTilesMap = Map[Int, List[(Int, Int)]]
for (x <- 0 until Constant.boardWidth; y <- 0 until Constant.boardHeight) yield {
if (hasOpenTile(board, x, y)){
// add to values to openTilesMap
}
}
openTilesMap
}
However my IDE shows error as:
Expression of type (Seq[(Int, List[Int, Int])]) => Map[Int, List[(Int, Int)]] doesn't conform to expected type Map[Int, List[(Int, Int)]]
Does it mean that val openTilesMap = Map[Int, List[(Int, Int)]] creates Seq of Tuples (Int, List[Int, Int]) instead of Map? If so, how can i make it return Map?
// edit
I'm trying to write a bot to javascript game. I'm mapping a board of tiles. In the mentioned method I am trying to find all "open tiles" (tiles which are not fully surounded by other tiles, thus can be moved) and in the return i would like to have a Map where key is a tile number with coordinates as values. In next step i want to find if it is possible to find path between "open" tiles with the same number.
I think the problem is the line
val openTilesMap = Map[Int, List[(Int, Int)]]
You should try this:
val openTilesMap: Map[Int, List[(Int, Int)]] = Map()
Your version assigns the type Map[Int, List[(Int, Int)]] to the value openTilesMap.
Related
I'm pretty new to scala and I can't find a way to get rid of my Array[Seq[(Int, String)]] to one big Seq[(Int, String)] containing the (Int, String) of each Seq[(Int, String)].
Here is a more explicit example:
Array[Seq[(Int, String)]]:
ArrayBuffer((1,a), (1,group), (1,of))
ArrayBuffer((2,following), (2,clues))
ArrayBuffer((3,three), (3,girls))
And here is what I want my Seq[(Int, String)]] to looks like:
Seq((1,a), (1,group), (1,of), (2,following), (2,clues), (3,three), (3,girls))
You are looking for flatten: val flat: Array[(Int, String)] = originalArray.flatten
If you want it to be a Seq rather than an array (good choice), just tuck a .toSeq at the end: originalArray.flatten.toSeq
I want to use reducebykey but when i try to use it, it show error:
type miss match required Nothing
question: How can I create a custom function for reducebykey?
{(key,value)}
key:string
value: map
example:
rdd = {("a", "weight"->1), ("a", "weight"->2)}
expect{("a"->3)}
def combine(x: mutable.map[string,Int],y:mutable.map[string,Int]):mutable.map[String,Int]={
x.weight = x.weithg+y.weight
x
}
rdd.reducebykey((x,y)=>combine(x,y))
Lets say you have a RDD[(K, V)] (or PairRDD[K, V] to be more accurate) and you want to somehow combine values with same key then you can use reduceByKey which expects a function (V, V) => V and gives you the modified RDD[(K, V)] (or PairRDD[K, V])
Here, your rdd = {("a", "weight"->1), ("a", "weight"->2)} is not real Scala and similary the whole combine function is wrong both syntactically and logically (it will not compile). But I am guessing that what you have is something like following,
val rdd = sc.parallelize(List(
("a", "weight"->1),
("a", "weight"->2)
))
Which means that your rdd is of type RDD[(String, (String, Int))] or PairRDD[String, (String, Int)] which means that reduceByKey wants a function of type ((String, Int), (String, Int)) => (String, Int).
def combine(x: (String, Int), y: (String, Int])): (String, Int) =
(x._1, x._2 + y._2)
val rdd2 = rdd.reducebykey(combine)
If your problem is something else then please update the question to share your problem with real code, so that others can actually understand it.
I want to write a method that gets a list of characters, and returns a list that each element of it will be a (indexOfelement, element) tuple.
As you know, we can use the indexOf, as following:
def buggyAttempt (charsList: List[Char]): List[(Int, Char)] = charsList.map(char => (charsList.indexOf(char), char))
This works fine if there is no repetition within the elements. So the question is, how to deal with the a list of repeated characters? For example if I feed it List("a", "b", "c", "c"), I will get List((0,a), (1,b), (2,c), (3,c)).
I want to solve this problem in a functional manner, so no mutable variables.
First of all, here is the version of your code that compiles:
def notBuggyAttempt (charsList: List[Char]): List[(Int, Char)] = {
charsList.map(char => (charsList.indexOf(char), char))
}
This will return the tuples with only the first indices.
To obtain what you want, though, you may use zipWIthIndex, which returns List[(Char, Int)], then, if you want a List[(Int, Char)], you have to swap the elements:
def getIndexTuples (charsList: List[Char]): List[(Int, Char)] = {
charsList.zipWithIndex.map(_.swap)
}
Lets say your input is
val input = List('a','b','c','c')
you can get the output using
input.zipWithIndex.collect{
case (t1,t2) => (t2,t1)
}
Output will be
res0: List[(Int, Char)] = List((0,a), (1,b), (2,c), (3,c))
Use zipWithIndex with map as below:
x.zipWithIndex.map(v=>(v._2,v._1))
In Scala REPL:
scala> val x = List("a", "b", "c", "c")
x: List[String] = List(a, b, c, c)
scala> x.zipWithIndex.map(v=>(v._2,v._1))
res22: List[(Int, String)] = List((0,a), (1,b), (2,c), (3,c))
Using IndexOf() makes multiple parsings on the list. If the list is very large there will be significant performance overheads.
Suppose I am adding an optional entry of type Option[(Int, String)] to Map[Int, String]
def foo(oe: Option[(Int, String)], map: Map[Int, String]) = oe.fold(map)(map + _)
Now I wonder how to add a few optional entries:
def foo(oe1: Option[(Int, String)],
oe2: Option[(Int, String)],
oe3: Option[(Int, String)],
map: Map[Int, String]): Map[Int, String] = ???
How would you implement it ?
As I mention in a comment above, Scala provides an implicit conversion (option2Iterable) that allows you to use Option as a collection of one or zero objects in the context of other types in the collection library.
This has some annoying consequences, but it does provide the following nice syntax for your operation:
def foo(oe1: Option[(Int, String)],
oe2: Option[(Int, String)],
oe3: Option[(Int, String)],
map: Map[Int, String]): Map[Int, String] = map ++ oe1 ++ oe2 ++ oe3
This works because the ++ on Map takes an GenTraversableOnce[(A, B)], and the Iterable that you get from option2Iterable is a subtype of GenTraversableOnce.
There are lots of variations on this approach. You could also write map ++ Seq(oe1, oe2, oe3).flatten, for example. I find that less clear, and it involves the creation of an extra collection, but if you like it, go for it.
map ++ Seq(oe1, oe2, oe3).flatten
If the number of optional entries is variable I would use variable length arguments
def foo(map: Map[Int, String], os: Option[(Int, String)]*) = map ++ os.flatten
In my dao I receive a tuple[String,String] of which _1 is non-unique and _2 is unique. I groupBy based on _1 to get this -
val someCache : Map[String, List[(String, String)]]
This is obviously wasteful since _1 is being repeated for all values of the Map. Since _2 is unique, what I want is something like -
val someCache : Map[String, Set[String]]
i.e. group by _1 and use as key and use the paired _2s as value of type Set[String]
def foo(ts: Seq[(String, String)]): Map[String, Set[String]] = {
ts.foldLeft(Map[String, Set[String]]()) { (agg, t) =>
agg + (t._1 -> (agg.getOrElse(t._1, Set()) + t._2))
}
}
scala> foo(List(("1","2"),("1","3"),("2","3")))
res4: Map[String,Set[String]] = Map(1 -> Set(2, 3), 2 -> Set(3))
Straightforward solution is to map over all elements and convert each list to set:
someCache.map{ case (a, l) => a -> l.map{ _._2 }.toSet }
You could also use mapValues but you should note that it creates a lazy collection and performs transformation on every access to value.