I am trying to get the index of a row using Scala from a list consisting of lists of integers List[List[Int]]. I already have two functions that given the row index/column index and the grid as parameters, it outputs all the elements in that row. What I need is a function that given a particular element (eg: 0), it finds its row index and column index and puts them in a list: List[(Int, Int)]. I tried to code a function that gives back an index when encountering 0 and then I passed the function to the whole grid. I don't know if I'm doing it the right way. Also, I couldn't figure out how to return the list.
Also, I cannot use any loops.
Thanks in advance.
def Possibilities(): List[Int] = {
def getRowIndex(elem: Int): Int = elem match
{
case 0 => sudoku.grid.indexOf(sudoku.row(elem))
case x => x
}
val result1 = sudoku.grid map {row => row map getRowIndex}
}
I think with two dimensions it is much easier to write such a method with for comprehensions.
Given a List[List[Int]] like this:
val grid = List(
List(1, 2, 3),
List(4, 5, 6),
List(3, 2, 1))
we can simply walk through all the rows and columns, and check whether each element is the one we are looking for:
def possibilities(findElem: Int): List[(Int, Int)] = {
for (
(row, rowIndex) <- grid.zipWithIndex;
(elem, colIndex) <- row.zipWithIndex
if elem == findElem
) yield (rowIndex, colIndex)
}
The yield keyword creates a collection of the results of the for loop. You can find more details on Scala's forloop syntax here (and a more thorough discussion on how this relates to map, flatMap, etc. here).
So, if you don't want to use a for loop, simply 'translate' it into an equivalent expression using map. flatMap, and withFilter:
def possibilities(findElem: Int): List[(Int, Int)] = {
grid.zipWithIndex flatMap { rowAndIndex =>
rowAndIndex._1.zipWithIndex.withFilter(_._1 == findElem) map { colAndIndex =>
(rowAndIndex._2, colAndIndex._2)
}
}
}
Step 1, create a collection of all possible tuples of indices, with a for comprehension (for looks like a loop but it is not)
val tuples = for (i <- grid.indices; j <- grid.head.indices) yield (i, j)
Step 2, filter this collection
tuples.filter { case (i, j) => grid(i)(j) == valueToFind }
Related
Given a generic list, return a list containing the same objects in a tuple with their index in the list.
For example:
f ["a", "b"];
- val it = [(0,"a") , (1,"b")] : (int * string) list
The function should be a one-liner, meaning no pattern matching, recursion, if/else, helper functions and let/local. So far i could only make a list of indices given the input list:
fun f lst = List.take((foldl (fn (x,list) => [(hd(list)-1)]#list) [length(lst)] (lst)),length(lst));
f [#"a",#"b"];
- val it = [0, 1]: int List.list;
I should add the list items to these indices in a tuple but i'm not sure how to do that.
Here is a hint for one way to solve it:
1) Using List.sub, create an anonymous function which sends an index i to the pair consisting of i and the lst element at index i.
2) Map this over the result obtained by calling List.tabulate on length lst and the function which sends x to x.
I was able to get this to work (on one line), but the result is ugly compared to a straightforward pattern-matching approach. Other than as a puzzle, I don't see the motivation for disallowing that which makes SML an elegant language.
It appears that i forgot the #i operator to access the i'th element of a tuple. The answer is the following:
fun f xs = List.take((foldr (fn (x,list) => [(#1(hd(list))-1,x)]#list) [(length(xs),hd(xs))] (xs)),length(xs));
f (explode "Hello");
- val it = [(0, #"H"), (1, #"e"), (2, #"l"), (3, #"l"), (4, #"o")]: (int * char) List.list;
v1 = [1,2,3,4]
v2 = [1,2,3,4,5]
I need the sum of these lists: [2,4,6,8,5]
And is there any way to print elements that executes a+b= c , where c is for example 8 ?
How can I do that in scala?
You can use zipAll to zip the lists together. That method takes in two extra arguments that represents the element to use in case one list is longer than the other, and vice versa. Since you are adding the lists, you should use the additive identity 0. Then you can simply map over the generated list of tuples:
val v1 = List(1, 2, 3, 4)
val v2 = List(1, 2, 3, 4, 5)
v1.zipAll(v2, 0, 0).map { case (a, b) => a + b }
You can read the documentation of zipAll in the documentation of IterableLike. The most relevant part:
Returns a iterable collection formed from this iterable collection and another iterable collection by combining corresponding elements in pairs. If one of the two collections is shorter than the other, placeholder elements are used to extend the shorter collection to the length of the longer.
If you're looking to print out certain elements, you might choose to filter instead of map, and then use foreach:
v1.zipAll(v2, 0, 0).filter {
case(a, b) => a + b == 8
}.foreach {
case(a, b) => println(s"$a+$b=8")
}
Or just a foreach with more interesting case statements:
v1.zipAll(v2, 0, 0).foreach {
case(a, b) if a + b == 8 => println(s"$a+$b=8")
case _ =>
}
Or you could use collect, and ignore the return value:
v1.zipAll(v2, 0, 0).collect {
case(a, b) if a + b == 8 => println(s"$a+$b=8")
}
You might want to read some introductory text to the Scala collections library, like the one in the docs.
A similar approach to Ben's, using a for comprehension,
for ( (a,b) <- v1.zipAll(v2, 0, 0) if a+b == 8 ) yield (a,b)
which delivers those (zipped) pairs of values whose sum is 8.
I have a list in Scala that I'm trying to partition into multiple lists based on a predicate that involves multiple elements of the list. For example, if I have
a: List[String] = List("a", "ab", "b", "abc", "c")
I want to get b: List[List[String]] which is a List of List[String] such that the sum of the lengths of the inner List[String] == 3. i.e List(List("a", "b", "c"), List("abc"), List("ab", "a"), ...)
[Edit] Needs to take a reasonable time for lists of length 50 or less.
It is not possible to build an efficient algorithm that is cheaper than O(2^n * O(p)) for any arbitrary predicate, p. This is because every subset must be evaluated. You will never achieve something that works for n == 50.
Build all possible sublists and filter:
def filter[A](list: List[A])(predicate: (List[A] => Boolean)): List[List[A]] = {
(for {i <- 1 to list.length
subList <- list.combinations(i)
if predicate(subList)
} yield subList).toList
}
val a = List("a", "ab", "b", "abc", "c")
val result = filter(a)(_.foldLeft(0)(_ + _.length) == 3)
I think Sergey is on a good track here, but we can optimize his code a little bit. First of all, we can notice that if the sum of string lengths is N then for sure we don't need to check combinations composed of more than N strings, as the shortest string is at least one character long. And, additionally, we can get away without for synctatic sugar and use the sum method instead of a much more generic (and thus, probably, not so quick) foldLeft.
For clarity's sake, let's first define a small helper function which will compute the sum of strings lengths:
def sumOfStr(list: List[String]) = list.map(_.length).sum
And now the main method:
def split(list: List[String], sum: Int) =
(1 to sum).map(list.combinations(_).filter(sumOfStr(_) == sum)).flatten.toList
EDIT: With our powers combined, we give you a still very inefficient, but hey-that's-the-best-we-can-do-in-reasonable-time version:
def sumOfStr(lst: List[String]) = {
var sum = 0
lst.foreach{ sum += _.length }
sum
}
def split(lst: List[String], sum: Int) =
(1 to sum).par
.map(lst.combinations(_).filter(sumOfStr(_) == sum))
.flatten.toList
Let's say that I have a Map of strings -> List of Integers. I would like to create a function which takes in as a parameter a List of strings and returns all the integers correlating to all the string in that list. I.e. if the Map X contains the following mappings:
database = [("Bob",[1,2,3]),("John",[1,5,6]),("Trevor",[4,5,7])]
If this function takes in ["Bob","John"] as the list of names, it should return,
[1,2,3,5,6]
Since Bob correlates to 1,2,3 and John correlates to 1,5,6 (same entries for both names aren't duplicated). I also would like to not introduce a mutable variable if I don't have to, thus leading me to believe a for comprehension that yields this list of number values would be the best way to achieve this, but I'm not sure how.
If you want to use a for-comprehension you can so this:
val result = for {
key <- keys
nums <- map.get(key).toSeq
num <- nums
} yield num
result.distinct
Explanation:
for each key in the list try to get an entry and convert it to a Seq (necessary because flatMap expects a Seq in this case) and add every number in the list to the result. If the key is not present in the map the collection will be empty and therefore not yield any results. At the end call distinct to remove the duplicates.
val myMap = Map("Bob" -> List(1,2,3), "John" -> List(1,5,6), "Trevor" -> List(4,5,7))
val names = List("Bob", "John")
You can add default value to Map using method withDefaultValue:
val mapWithDefaul = myMap withDefaultValue Nil
Then you could use Map as function in flatMap:
names.flatMap(mapWithDefaul).distinct
// List(1, 2, 3, 5, 6)
Let
val db = Map("Bob" -> List(1,2,3), "John" -> List(1,5,6), "Trevor" -> List(4,5,7))
val names = List("Bob", "John")
Then a similar approach to #senia's using flatMap,
implicit class mapCorr[A,B](val db: Map[A,List[B]]) extends AnyVal {
def corr(keys: List[A]): List[B] = {
keys.flatMap{ k => db get k }.flatten.distinct
}
}
and
scala> db.corr(keys)
res0: List[Int] = List(1, 2, 3, 5, 6)
Here we allow for key lists of type A and maps from type A to type List[B] .
val myset = Set("Bob","John")
val database = Map(("Bob"->List(1,2,3)),("John"->List(1,5,6)),("Trevor"->List(4,5,7)))
val ids = database.filter(m => myset.contains(m._1)).map(_._2).flatten.toList.distinct
outputs:
ids: List[Int] = List(1, 2, 3, 5, 6)
Something like:
val result = database.filter(elem => list.contains(elem._1)).foldLeft(List())((res,elem) => res ++ elem._2)
where list is the input list of names.
This is the problem that I did solve, however being a total imperative Scala noob, I feel I found something totally not elegant. Any ideas of improvement appreciated.
val l1 = 4 :: 1 :: 2 :: 3 :: 4 :: Nil // original list
val insert = List(88,99) // list I want to insert on certain places
// method that finds all indexes of a particular element in a particular list
def indexesOf(element:Any, inList:List[Any]) = {
var indexes = List[Int]()
for(i <- 0 until inList.length) {
if(inList(i) == element) indexes = indexes :+ i
}
indexes
}
var indexes = indexesOf(4, l1) // get indexes where 4 appears in the original list
println(indexes)
var result = List[Any]()
// iterate through indexes and insert in front
for(i <- 0 until indexes.length) {
var prev = if(i == 0) 0 else indexes(i-1)
result = result ::: l1.slice(prev, indexes(i)) ::: insert
}
result = result ::: l1.drop(indexes.last) // append the last bit from original list
println(result)
I was thinking more elegant solution would be achievable with something like this, but that's just pure speculation.
var final:List[Any] = (0 /: indexes) {(final, i) => final ::: ins ::: l1.slice(i, indexes(i))
def insert[A](xs: List[A], extra: List[A])(p: A => Boolean) = {
xs.map(x => if (p(x)) extra ::: List(x) else List(x)).flatten
}
scala> insert(List(4,1,2,3,4),List(88,99)){_ == 4}
res3: List[Int] = List(88, 99, 4, 1, 2, 3, 88, 99, 4)
Edit: explanation added.
Our goal here is to insert a list (called extra) in front of selected elements in another list (here called xs--commonly used for lists, as if one thing is x then lots of them must be the plural xs). We want this to work on any type of list we might have, so we annotate it with the generic type [A].
Which elements are candidates for insertion? When writing the function, we don't know, so we provide a function that says true or false for each element (p: A => Boolean).
Now, for each element in the list x, we check--should we make the insertion (i.e. is p(x) true)? If yes, we just build it: extra ::: List(x) is just the elements of extra followed by the single item x. (It might be better to write this as extra :+ x--add the single item at the end.) If no, we have only the single item, but we make it List(x) instead of just x because we want everything to have the same type. So now, if we have something like
4 1 2 3 4
and our condition is that we insert 5 6 before 4, we generate
List(5 6 4) List(1) List(2) List(3) List(5 6 4)
This is exactly what we want, except we have a list of lists. To get rid of the inner lists and flatten everything into a single list, we just call flatten.
The flatten trick is cute, I wouldn't have thought of using map here myself. From my perspective this problem is a typical application for a fold, as you want go through the list and "collect" something (the result list). As we don't want our result list backwards, foldRight (a.k.a. :\) is here the right version:
def insert[A](xs: List[A], extra: List[A])(p: A => Boolean) =
xs.foldRight(List[A]())((x,xs) => if (p(x)) extra ::: (x :: xs) else x :: xs)
Here's another possibility, using Seq#patch to handle the actual inserts. You need to foldRight so that later indices are handled first (inserts modify the indices of all elements after the insert, so it would be tricky otherwise).
def insert[A](xs: Seq[A], ys: Seq[A])(pred: A => Boolean) = {
val positions = xs.zipWithIndex filter(x => pred(x._1)) map(_._2)
positions.foldRight(xs) { (pos, xs) => xs patch (pos, ys, 0) }
}