how to convert List(String,String) to ListMap[String,String]? - scala

I have a list of type List(String,String) and I wanted to convert it to map. When I used toMap method I found that it does not preservers the order of data that is there in the List. However my goal is to convert the list to Map by keeping the order of the data same as of List. I learned that ListMap preserves the insertion order(but it is immutable) so I can use the LinkedHashMap with map function to insert the data sequentially into LinkedHashMap but that means I need to iterate over all the elements which is pain. Can anyone please suggest me a better approach?
Thanks

This should do it :
val listMap = ListMap(list : _*)

In Scala 2.13 or later:
scala> import scala.collection.immutable.ListMap
import scala.collection.immutable.ListMap
scala> val list = List((1,2), (3,4), (5,6), (7,8), (9,0))
list: List[(Int, Int)] = List((1,2), (3,4), (5,6), (7,8), (9,0))
scala> list.to(ListMap)
res3: scala.collection.immutable.ListMap[Int,Int] = ListMap(1 -> 2, 3 -> 4, 5 -> 6, 7 -> 8, 9 -> 0)

Don't use a ListMap. They are extremely imperformant. Since they are structured as lists they have linear lookup performance (https://docs.scala-lang.org/overviews/collections/performance-characteristics.html)
I'd advise instanciating a mutable LinkedHashmap and then assigning it to a val defined as a collections.Map. The collection.Map interface doesn't expose mutable methods so the map is immutable to any entity accessing it.

Related

scala: Create a Sequence of tuples with a constant key

Given a constant value and a potentially long Sequence:
a:String = "A"
bs = List(1, 2, 3)
How can you most efficiently construct a Sequence of tuples with the first element equalling a?
Seq(
( "A", 1 ),
( "A", 2 ),
( "A", 3 )
)
Just use a map:
val list = List(1,2,3)
list.map(("A",_))
Output:
res0: List[(String, Int)] = List((A,1), (A,2), (A,3))
Since the most efficient would be to pass (to further receiver) just the seq, and the receiver tuple the elements there, I'd do it with views.
val first = "A"
val bs = (1 to 1000000).view
further( bs.map((first, _)) )
You can do it using map just like in the answer provided by #Pedro or you can use for and yield as below:
val list = List(1,2,3)
val tuple = for {
i <- list
} yield ("A",i)
println(tuple)
Output:
List((A,1), (A,2), (A,3))
You are also asking about the efficient way in your question. Different developers have different opinions between the efficiency of for and map. So, I guess going through the links below gives you more knowledge about the efficiency part.
for vs map in functional programming
Scala style: for vs foreach, filter, map and others
Getting the desugared part of a Scala for/comprehension expression?

Is there a way to maintain ordering with Scala's breakOut?

I recently discovered breakOut and love how elegant it is, but noticed that it doesn't maintain order.
eg (from REPL):
scala> val list = List("apples", "bananas", "oranges")
list: List[String] = List(apples, bananas, oranges)
scala> val hs: HashMap[String, Int] = list.map{x => (x -> x.length)}(breakOut)
hs: scala.collection.mutable.HashMap[String,Int] = Map(bananas -> 7, oranges -> 7, apples -> 6)
I like using breakOut since it's really clean and neat but ordering does matter to me. Is there a way to get it to maintain order or do I have to add elements to my hashmap one at a time?
You see this behavior, because of the fact that HashMap is a data structure with undefined order. Even if you see some ordering of the elements in the hash map and it's consistent across the runs, you shouldn't depend on it. If you really need the order, consider using LinkedHashMap

How to implement GetResult[List[String]] in scala slick?

I'm use SQLActionBuilder, such as seq"""select ...""", to create a common/wide sql query and I not care about the result column count it is.
Document example use as[TupleX] to decided result type,in my stage, I want use List[String] replace TupleX type.
I have attempted with sQLActionBuilder.as[List[String]] but a compile error encounter:
Error:(8, 187) could not find implicit value for parameter rconv: slick.jdbc.GetResult[List[String]]
val x = reportUtilRepository.find(List())("td_report_region")(1469635200000L, 1475251200000L)("region" :: Nil, "clicks" :: "CPC" :: Nil)(List("1", "2"), List("regionType" -> "1"))(_.as[List[String]]).map(x => println(x.toString))
and sQLActionBuilder.as[List[(String, String, String)]] works well. So how can I use List[String] to match a common result.
I think a straight way is implement a GetResult[List[String]] as compiler tips but I don't know how to do it.Other ways also welcome.
Thanks.
First of all querying database always returns a list of tuples, so the result type will be List[TupleX] because each row is represented as a list record and then columns in each row are respectively tuple elements.
Therefore, your data will look like List((1,2,3),(3,4,5)) where data type is List[(Int, Int, Int)]. To produce List[Int] you might do following:
val a = List((1,2,3),(3,4,5))
a map {x => List(x._1, x._2, x._3)} flatten
res0: List[Int] = List(1, 2, 3, 3, 4, 5)

How to use priority queues in Scala?

I am trying to implement A* search in Scala (version 2.10), but I've ran into a brick wall - I can't figure out how to use Scala's Priority Queue.
I have a set of squares, represented by (Int, Int)s, and I need to insert them with priorities represented by Ints. In Python you just have a list of key, value pairs and use the heapq functions to sort it.
So how do you do this?
There is actually pre-defined lexicographical order for tuples -- but you need to import it:
import scala.math.Ordering.Implicits._
Moreover, you can define your own ordering.
Suppose I want to arrange tuples, based on the difference between first and second members of the tuple:
scala> import scala.collection.mutable.PriorityQueue
// import scala.collection.mutable.PriorityQueue
scala> def diff(t2: (Int,Int)) = math.abs(t2._1 - t2._2)
// diff: (t2: (Int, Int))Int
scala> val x = new PriorityQueue[(Int, Int)]()(Ordering.by(diff))
// x: scala.collection.mutable.PriorityQueue[(Int, Int)] = PriorityQueue()
scala> x.enqueue(1 -> 1)
scala> x.enqueue(1 -> 2)
scala> x.enqueue(1 -> 3)
scala> x.enqueue(1 -> 4)
scala> x.enqueue(1 -> 0)
scala> x
// res5: scala.collection.mutable.PriorityQueue[(Int, Int)] = PriorityQueue((1,4), (1,3), (1,2), (1,1), (1,0))
Indeed, there is no implicit ordering on pairs of integers (a, b). What would it be? Perhaps they are both positive and you can use (a - 1.0/b)? Or they are not, and you can use, what, (a + atan(b/pi))? If you have an ordering in mind, you can consider wrapping your pairs in a type that has your ordering.

Immutable Scala Map implementation that preserves insertion order [duplicate]

This question already has answers here:
Scala Map implementation keeping entries in insertion order?
(6 answers)
Closed 7 years ago.
LinkedHashMap is used to preserve insertion order in the map, but this only works for mutable maps. Which is the immutable Map implementation that preserves insertion order?
ListMap implements an immutable map using a list-based data structure, and thus preserves insertion order.
scala> import collection.immutable.ListMap
import collection.immutable.ListMap
scala> ListMap(1 -> 2) + (3 -> 4)
res31: scala.collection.immutable.ListMap[Int,Int] = Map(1 -> 2, 3 -> 4)
scala> res31 + (6 -> 9)
res32: scala.collection.immutable.ListMap[Int,Int] = Map(1 -> 2, 3 -> 4, 6 -> 9)
The following extension method - Seq#toListMap can be quite useful when working with ListMaps.
scala> import scalaz._, Scalaz._, Liskov._
import scalaz._
import Scalaz._
import Liskov._
scala> :paste
// Entering paste mode (ctrl-D to finish)
implicit def seqW[A](xs: Seq[A]) = new SeqW(xs)
class SeqW[A](xs: Seq[A]) {
def toListMap[B, C](implicit ev: A <~< (B, C)): ListMap[B, C] = {
ListMap(co[Seq, A, (B, C)](ev)(xs) : _*)
}
}
// Exiting paste mode, now interpreting.
seqW: [A](xs: Seq[A])SeqW[A]
defined class SeqW
scala> Seq((2, 4), (11, 89)).toListMap
res33: scala.collection.immutable.ListMap[Int,Int] = Map(2 -> 4, 11 -> 89)
While ListMap will preserve insertion order, it is not very efficient - e.g. lookup time is linear. I suggest you create a new collection class which wraps both the immutable.HashMap and the immutable.TreeMap. The immutable map should be parametrized as immutable.HashMap[Key, (Value, Long)], where the Long in the tuple gives you the pointer to the corresponding entry in the TreeMap[Long, Key]. You then keep an entry counter on the side. This tree map will sort the entries according to the insertion order.
You implement insertion and lookup in the straightforward way - increment the counter, insert into the hash map and insert to the the counter-key pair into the treemap. You use the hash map for the lookup.
You implement iteration by using the tree map.
To implement remove, you have to remove the key-value pair from the hash map and use the index from the tuple to remove the corresponding entry from the tree map.