I'm working on a problem to take two lists, for example (1,2,3) and (a,b) and return a list ((1,a)(1,b)(2,a)(2,b)(3,a)(3,b)) using only map and flatten.
This problem requires me to define a function as follows:
def product[A](xs: List[A], ys: List[A])= {
And within this function get the result. I'm rather new to Scala and I am used to languages like python and java.
I've gotten this far:
def product[A](xs: List[A], ys: List[A])= {
for(y <- ys){
println(xs.map(x=> (x,y)))
}
}
This will return something like this:
List((1,a), (2,a), (3,a))
List((1,b), (2,b), (3,b))
I'm not sure how can combine these lists now. In python I would do something like create a new list variable, append both of these lists to that list, and then flatten it so I would have one list. However, I'm rather confused by scala as it seems as if I am not allowed to define a new variable within a function. How can I combine these lists and flatten them at this point?
Product List using only map and flatten
val nums = List(1, 2, 3)
val chars = List('a', 'b')
nums.map { a => chars.map { b => (a, b) } }.flatten
Scala REPL
scala> nums.map(a => chars.map(b => (a, b)))
res5: List[List[(Int, Char)]] = List(List((1, 'a'), (1, 'b')), List((2, 'a'), (2, 'b')), List((3, 'a'), (3, 'b')))
scala> nums.map(a => chars.map(b => (a, b))).flatten
res6: List[(Int, Char)] = List((1, 'a'), (1, 'b'), (2, 'a'), (2, 'b'), (3, 'a'), (3, 'b'))
Product List can be built using flatMap and map combination
nums.flatMap { a => chars.map { b => (a, b) }}
Product List can also be built using for comprehension
for {a <- nums; b <- chars} yield (a, b)
Scala REPL
scala> val nums = List(1, 2, 3)
val nums: List[Int] = List(1, 2, 3)
scala> val chars = List('a', 'b')
chars: List[Char] = List('a', 'b')
scala> nums.flatMap { a => chars.map { b => (a, b) }}
res2: List[(Int, Char)] = List((1, 'a'), (1, 'b'), (2, 'a'), (2, 'b'), (3, 'a'), (3, 'b'))
scala> for {a <- nums; b <- chars} yield (a, b)
res3: List[(Int, Char)] = List((1, 'a'), (1, 'b'), (2, 'a'), (2, 'b'), (3, 'a'), (3, 'b'))
You can solve it using for comprehension. It's actually a syntactic sugar for map and flatMap:
def product[A](xs: List[A], ys: List[A])= {
for {
x <- xs
y <- ys
} yield {
x -> y
}
}
For-comprehensions is the Scala idiomatic way to achieve this. It's more readable and maintainable, and the underlying operations are still map and flatMap. In fact, even for types that are not collections, but still have map and flatMap, it's common to use for comprehensions (Futures, Options, Trys, etc.)
Edit
If you want to continue with your solution and save the lists and combine them, you'll have to drop the println and add a yield, and then flatten the main list that was created:
def product[A](xs: List[A], ys: List[A]) = {
for (y <- ys) yield {
xs.map(x => (x, y))
}
}
val res = product(List(1, 2, 3), List("a", "b"))
println(res.flatten)
val ls1 = List(1,2,3)
val ls2 = List('a','b')
def product[A](xs: List[A], ys: List[A])= xs.map(x => ys.map((x,_))).flatten
product(ls1,ls2)
Related
So i need to implement a function that takes two lists and a function. The function then uses the elements of the two lists and applies the function on the elements and saves them into a list by using map and/or fold and the functions from the list class.
Example:
• zipWith((x: Int, y: Int) => x + y, List(1, 2, 3), List(4, 5, 6))
→ List(5, 7, 9)
• zipWith((x:Int,y:Int) => x, List(1,2,3), List(4,5,6))
→ List(1, 2, 3)
I do not know how to use the passed function and apply it on the two lists. My idea was to zip the two lists and then apply the function on every element of the zipped list.
The elegant solution is using pattern matching:
def zipWith[A, B, C](f: (A, B) => C, l1: List[A], l2: List[B]): List[C] = {
l1.zip(l2).map { case (x1, x2) => f(x1, x2) }
}
To solve this without pattern matching, you'll just need to access the tuple's fields directly:
def zipWith[A, B, C](f: (A, B) => C, l1: List[A], l2: List[B]): List[C] = {
l1.zip(l2).map(tuple => f(tuple._1, tuple._2))
}
Since you asked for a solution without pattern matching, I suggest the following one:
def zipWith[A, B, C](a: List[A], b: List[B])(f: (A, B) => C): List[C] = {
a.zip(b).map { tuple =>
f(tuple._1, tuple._2)
}
}
By moving f to a separate arguments list, your invocations could be shortened significantly:
val a = List(1, 2, 3)
val b = List(4, 5, 6)
zipWith(a, b)(_ + _) // List(5, 7, 9)
zipWith(a, b)(_ * _) // List(4, 10, 18)
I have a list of lists with the following data
val list = List(List("a","b","c"),List("d","e","f"),List("a","a","a"))
I want to disicover how many different data do I have in each position of the sublists
1 -> List("a","d","a")
2 -> List("b","e","a")
3 -> List("c","f","a")
Is there a way to do that? It doesn't need to be indexed, but I need the amount of different values per sublist index, the result could also be
2 // different values a and d
3 // different values b, e and a
3 // different values c, f and a
As I noted in a comment on Jhonny Everson's (almost right but now deleted) answer, you can use transpose to get a list of the columns, and then distinct to remove duplicates:
scala> list.transpose.map(_.distinct.size)
res0: List[Int] = List(2, 3, 3)
This will throw an exception if all the lists don't have the same size, but that's probably what you want.
scala> list.transpose.map(_.toSet.size)
res0: List[Int] = List(2, 3, 3)
The output of list.transpose is List(List(a, d, a), List(b, e, a), List(c, f, a)) which gives you the structure you want then map each List to a Set to get the unique elements and count them.
If you want unique elements per position, then you can use zipWithIndex and reverse the outputs.
scala> list.transpose.map(_.distinct).zipWithIndex.map(t => t._2 -> t._1)
res1: List[(Int, List[String])] = List((0,List(a, d)), (1,List(b, e, a)), (2,List(c, f, a)))
Here is the code you wanted:
var lOfl = List(List.range(1,5), List(2,2,2,3), Nil)
//> lOfl : List[List[Int]] = List(List(1, 2, 3, 4), List(2, 2, 2, 3), List())
for {
l <- lOfl
} yield l.toSet.count(_ => true) //> res1: List[Int] = List(4, 2, 0)
A sample list of list of Int is created as lOfl; for loop iterates through each list of Int; toSet converts list to set eliminating duplicate elements. then count function does as the name says it all.
OR use the Scala's most used collection function (:P :P), map, like below,
lOfl.map(l => l.toSet.count(_ => true) ) //> res2: List[Int] = List(4, 2, 0)
I have a question about Haskell. I want to know how I can create a list of data from two lists, one with data, an other with some key values. I'll explain it with an example:
Given two lists: [('a', "red"), ('b', "blue"), ('c', "green")] and [('a','b'), ('b', 'c'), ('c','a')]. Now I want to change the values of the second list with their colors given in the first list. So the function should return [("red","blue"), ("blue","green"), ("blue","red")].
I was thinking about list comprehension, but I'm very new to Haskell and I have no idea how I should do that. Or is there an easier way to do this?
This is probably a dumb question, but if someone can give me an example, I might get used to the think process of Haskell a bit more.
Another way would be to use Map
import Data.Maybe (mapMaybe)
import Data.Map (lookup
,fromList)
import Prelude hiding (lookup)
main :: IO ()
main = do
let a = [('a', "red"), ('b', "blue"), ('c', "green")]
b = [('a','b'), ('b', 'c'), ('c','a')]
table = fromList a
print $ mapMaybe (maybePair . (\(x,y) -> (x `lookup` table,
y `lookup` table ))) b
maybePair :: (Maybe a, Maybe b) -> Maybe (a,b)
maybePair (Just x,Just y) = Just (x, y)
maybePair _ = Nothing
Edit:
with the help of arrows the last anonymous function can be condensed to
import Control.Arrow ((***))
[…]
main :: IO ()
main = do
let a = [('a', "red"), ('b', "blue"), ('c', "green")]
b = [('a','b'), ('b', 'c'), ('c','a')]
table = fromList a
f x = x `lookup` table
print $ mapMaybe (maybePair . (f *** f)) b
[…]
-- second element from first (head) dropping tuples with bad key
color :: Eq a => a -> [(a, b)] -> b
color c = snd.head.dropWhile ((/=c).fst)
recolor a b = map (\(x, y) -> (color x a, color y a)) b
running
Prelude> recolor [('a', "red"), ('b', "blue"), ('c', "green")] [('a','b'), ('b', 'c'), ('c','a')]
[("red","blue"),("blue","green"),("green","red")]
If you consider an element of the second list cannot be found in the first list. You can write
color :: Eq b => b -> [(b, a)] -> Maybe a
color c = fmap snd.listToMaybe.dropWhile ((/=c).fst)
then
Prelude> recolor [('a',"red"),('b',"blue"),('c',"green")] [('a','h'),('u','c'),('c','a')]
[(Just "red",Nothing),(Nothing,Just "green"),(Just "green",Just "red")]
(you need import Data.Maybe (listToMaybe))
Another solution without need of importing any library but using tail recursion:
keyColor = [('a', "red"), ('b', "blue"), ('c', "green")]
keys = [('a','b'), ('b', 'c'), ('c','a')]
colors [] _ = [] -- no keys returns the empty list
colors _ [] = [] -- no colors returns the empty list
colors xs ys = colors_helper (xs, ys, []) -- tail recursion
colors_helper ([], _, acc) = acc
colors_helper (((k1, k2):xs), ys, acc) =
colors_helper (xs, ys, acc ++ [(color (k1, ys), color (k2, ys))])
where
-- converts value to color
color (val, ys) = snd $ head $ filter ( \(k, v) -> k == val ) ys
test:
> colors keys keyColor
> [("red","blue"),("blue","green"),("green","red")]
> colors keys []
> []
> colors [] keyColor
> []
I'm brand new to Scala, having had very limited experience with functional programming through Haskell.
I'd like to try composing a list of all possible pairs constructed from a single input list. Example:
val nums = List[Int](1, 2, 3, 4, 5) // Create an input list
val pairs = composePairs(nums) // Function I'd like to create
// pairs == List[Int, Int]((1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 1) ... etc)
I tried using zip on each element with the whole list, hoping that it would duplicate the one item across the whole. It didn't work (only matched the first possible pair). I'm not sure how to repeat an element (Haskell does it with cycle and take I believe), and I've had trouble following the documentation on Scala.
This leaves me thinking that there's probably a more concise, functional way to get the results I want. Does anybody have a good solution?
How about this:
val pairs = for(x <- nums; y <- nums) yield (x, y)
For those of you who don't want duplicates:
val uniquePairs = for {
(x, idxX) <- nums.zipWithIndex
(y, idxY) <- nums.zipWithIndex
if idxX < idxY
} yield (x, y)
val nums = List(1,2,3,4,5)
uniquePairs: List[(Int, Int)] = List((1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5), (3, 4), (3, 5), (4, 5))
Here's another version using map and flatten
val pairs = nums.flatMap(x => nums.map(y => (x,y)))
List[(Int, Int)] = List((1,1), (1,2), (1,3), (1,4), (1,5), (2,1), (2,2), (2,3), (2,4), (2,5), (3,1), (3,2), (3,3), (3,4), (3,5), (4,1), (4,2), (4,3), (4,4), (4,5), (5,1), (5,2) (5,3), (5,4), (5,5))
This can then be easily wrapped into a composePairs function if you like:
def composePairs(nums: Seq[Int]) =
nums.flatMap(x => nums.map(y => (x,y)))
How do I perform an operation that checks the IDs and removes the different elements of the first list and adds the different elements of the second list?
The letters are a Entity Id. The numbers are a object reference in memory.
List 1: A:1, B:2, C:3, D:4, E:5
List 2: B:6, C:7, E:8, F:9
RemovedElements: A:1, D:4
InvalidElements: B:6, C:7, E:8
ResultList: B:2, C:3, E:5, F:9
Does anyone know if there is any function that performs this operation?
scala> val l1 = Seq(('A', 1), ('B', 2), ('C', 3), ('D', 4), ('E', 5))
l1: Seq[(Char, Int)] = List((A,1), (B,2), (C,3), (D,4), (E,5))
scala> val l2 = Seq(('B', 6), ('C', 7), ('E', 8), ('F', 9))
l2: Seq[(Char, Int)] = List((B,6), (C,7), (E,8), (F,9))
scala> l2 map { e =>
| l1.find(_._1 == e._1).getOrElse(e)
| }
res51: Seq[(Char, Int)] = List((B,2), (C,3), (E,5), (F,9))