2

I am trying to convert Array[(String,String)] to Map[String,String] in scala.

I am trying toMap to convert to map.

Problem : It is changing the order of values.

Expectation : Order should not be changed.

Thanks

Andrey Tyukin
  • 43,673
  • 4
  • 57
  • 93
avy
  • 417
  • 1
  • 9
  • 21
  • 2
    Possible duplicate of [Scala Map implementation keeping entries in insertion order?](https://stackoverflow.com/questions/3835743/scala-map-implementation-keeping-entries-in-insertion-order) – Xavier Guihot Mar 23 '18 at 13:47
  • 1
    The question is nonsensical, because there is no such thing as `Array[String, String]`, at least not with the standard definition of `Array`. – Andrey Tyukin Mar 23 '18 at 13:52
  • 2
    It's also confusing to talk about order of values in a map which is an unordered data structure (apart from special implementations such as SortedMap). – slouc Mar 23 '18 at 14:03
  • 1
    Do you mean `Array[(String, String)]`? – James Whiteley Mar 23 '18 at 14:23

3 Answers3

3

I think this will work...

LinkedHashMap class implements mutable maps using a hashtable. The iterator and all traversal methods of this class visit elements in the order they were inserted.

scala> val arr = Array(("something","else"),("foo","a"),("bar","b"),("some","c"),("a1","b1"),("a2","b2"),("a3","b3"),("a4","b4"),("a5","b5"),("a6","c6"))
arr: Array[(String, String)] = Array((something,else), (foo,a), (bar,b), (some,c), (a1,b1), (a2,b2), (a3,b3), (a4,b4), (a5,b5), (a6,c6))

scala> val testMap =  scala.collection.mutable.LinkedHashMap[String,String]()
testMap: scala.collection.mutable.LinkedHashMap[String,String] = Map()

arr.foreach(x=> testMap += (x._1 ->x._2))

scala> testMap
res1: scala.collection.mutable.LinkedHashMap[String,String] = Map(something -> else, foo -> a, bar -> b, some -> c, a1 -> b1, a2 -> b2, a3 -> b3, a4 -> b4, a5 -> b5, a6 -> c6)
jwvh
  • 50,871
  • 7
  • 38
  • 64
0

After Comments:

It looks like the naive approach would not work in a sense that the order of the keys would be preserved. Here is a very useful test script from

andrey-tyukin

  for (s <- 1 until 100) {
    val keys = (1 to s).map(_.toString).toList
    val arr: Array[(String, String)] = keys.map { x => (x, x) }.toArray
    val m = arr.toMap
    val newKeysOrder = m.map(_._1).toList println (s + ": " + (keys == newKeysOrder))
  }

Basically it shows that the this approach is no good.

Array(("foo","a"), ("bar", "b"), ("baz", "c")).toList.toMap

I would however advise to avoid mutable data structures.

New Anser:

I would just use another simple construct from scala.collection.immutable.ListMap :

val m = ListMap(arr:_*)

And here is a script that tests if it's o.k. basically it's true for first 100 ints

  for (s <- 1 until 100) {
    val keys = (1 to s).map(_.toString).toList
    val arr: Array[(String, String)] = keys.map { x => (x, x) }.toArray
    val m = ListMap(arr: _*)
    val newKeysOrder = m.keys.toList
    println(s + ": " + (keys == newKeysOrder))
  }
Marko Švaljek
  • 2,071
  • 1
  • 14
  • 26
  • Please read the other answers and comments before answering. This does NOT preserve order as the OP requested. Edit: Since the other post has been deleted, you obviously can't check the other answers now. But try this out on a larger collection. You will see it does not preserve order – Jordan Cutler Mar 23 '18 at 16:21
  • I did try on up to 10 items there and thought it's fine ... I'll have a look at larger collection, have to commute now will give it a look in the evening. It might also be wrong answer, as far as I tried it worked. – Marko Švaljek Mar 23 '18 at 16:27
  • Try this. `val a = for (i <- 1 to 5; j <- 6 to 10) yield ("" + i, "" + j)` `val b = a.toList` `b.toMap` `res9: scala.collection.immutable.Map[String,String] = Map(4 -> 10, 5 -> 10, 1 -> 10, 2 -> 10, 3 -> 10)` I think issues may occur when there are collisions – Jordan Cutler Mar 23 '18 at 16:31
  • 1
    Here is another fun little script to experiment with, if you want: `for (s <- 1 until 100) { val keys = (1 to s).map(_.toString).toList val arr: Array[(String, String)] = keys.map{x => (x, x)}.toArray val m = arr.toMap val newKeysOrder = m.map(_._1).toList println(s + ": " + (keys == newKeysOrder)) } ` For this particular choice of keys, it seems to preserve the order for tiny maps of size up to `4`. – Andrey Tyukin Mar 23 '18 at 16:40
  • Thanks for providing the script :) at least I would like to avoid mutable then. I'll update my answer. – Marko Švaljek Mar 23 '18 at 18:26
0

You can use ListMap which implements immutable maps by using a list-based data structure.

ListMap maintains insertion order and returns ListMap.

1.Create an array

 val arr=Array(("a","Alice"),("b","Bob"),("c","Cat"),("d","Dog"))

2.Create ListMap

import scala.collection.immutable._
val listMap=arr.foldLeft(ListMap[String,String]())((prev,next)=>prev+(next._1->next._2))

3.It will produce below output

listMap: scala.collection.immutable.ListMap[String,String] = Map(a -> Alice, b -> Bob, c -> Cat, d -> Dog)
Manoj Kumar Dhakad
  • 1,862
  • 1
  • 12
  • 26