toMap function is shuffling my elements, why is that and how can I prevent it

huangapple go评论52阅读模式
英文:

toMap function is shuffling my elements, why is that and how can I prevent it

问题

The issue you're encountering is due to the fact that HashMap does not guarantee a specific order of elements, whereas you need your keys to be in a specific order. To maintain the order, you should use a List of tuples instead of a Seq when creating your map. Here's how you can modify your code:

val seq = List(("Test", DBType.Int), ("Test2", DBType.Int), ("Test3", DBType.Int))
val seqMap = seq.toMap

println(seqMap)

By using a List, you ensure that the order of elements is preserved when you create the map. This way, you'll get the expected output with keys in the same order as in your original seq.

英文:

.toMap shuffles my Items around / changes the order they were in, this messes with other parts of my code.

For example:

val seq = Seq("Test" -> DBType.Int, "Test2" -> DBType.Int, "Test3" -> DBType.Int);

val seqMap = seq.toMap;

println(seqMap)

The Output of this will be as expected:

Map(Test -> Int, Test2 -> Int, Test3 -> Int)

However, if I add more elements like this it gets weird:

val seq = Seq("Test" -> DBType.Int, "Test2" -> DBType.Int, "Test3" -> DBType.Int, "Test4" -> DBType.Int, "Test5" -> DBType.Int, "Test6" -> DBType.Int);
val seqMap = seq.toMap;

println(seqMap);

This will, and I really wanna know why, output this (the order has changed):

HashMap(Test3 -> Int, Test6 -> Int, Test5 -> Int, Test -> Int, Test4 -> Int, Test2 -> Int)

What the heck ? Did I not format it correctly ? Did I miss a comma ? I am really at the end of my expertise here.

I tried debugging it for almost an hour and a half but could not fix it. My idea would be that the .toMap function reshuffles the entire thing due to it being a HashMap now rather than a map, maybe the code in the background functions differently.

I am expecting my Seq of Tuples to be matches in order by the Map, as I need the keys to be in a specific (given) order.

I really hope someone can enlighten my why it behaves like this. I also did some google-ing but it just said: Use a Seq ! Well - duh - I am.

If you guys need more information on my code / problem feel free to comment.

EDIT: I am trying to join two tables together. One has a particular order of attributes and the other as well. My task is to join them in a fashion that the attributes of table 2 are being appended to those from table one. This however I have already managed. My problem is that the constructor of the schema class which is required to create a table wants to put these attributes in a map with the type they hold, f.e.: ("grade" -> Double)

So my order matters in that sens that the tests I am trying to full fill require me to have a specific order.

答案1

得分: 1

默认情况下,在Scala中,MapSet不会保证在迭代时以何种顺序返回项目。唯一保证顺序的基本集合是Seq

你可以在这里了解更多关于Scala中的Map的信息。文档还有一页描述了几种Map特征的具体实现,适合你的有:

ListMap 也在评论中提到,你可以像下面的示例一样使用它。

import scala.collection.immutable.ListMap

val seq = Seq("Test" -> 1, "Test2" -> 2, "Test3" -> 3)

seq.to(ListMap).foreach(println)

/* 输出:
 *
 * ```
 * (Test,1)
 * (Test2,2)
 * (Test3,3)
 * ```
 */

你可以在Scastie上试验这段代码

此外,需要注意的是,正如文档中所解释的,对于这种类型,某些操作的性能较差:

条目在内部以反向插入顺序存储,这意味着最新的键在列表的头部。因此,诸如 head 和 tail 等方法的时间复杂度为 O(n),而 last 和 init 的时间复杂度为 O(1)。插入或移除条目等其他操作也是 O(n),因此此集合仅适用于少量元素。

如果除了插入顺序外,你可能还可以依赖某种排序(例如键的字典顺序),你也可以使用 SortedMap

如果你愿意使用可变数据结构,Scala还拥有自己的 LinkedHashMap(在上面的评论中也有建议):

该类使用哈希表实现可变映射。该类的迭代器和所有遍历方法都以它们被插入的顺序访问元素。

最后,你还可以使用Java的 LinkedHashMap

Map 接口的哈希表和链表实现,具有可预测的迭代顺序。该实现与 HashMap 不同之处在于它维护一个双向链表,通过所有条目。这个链表定义了迭代顺序,通常是键插入到映射中的顺序(插入顺序)。请注意,如果在插入键之前 m.containsKey(k) 返回 true 的情况下调用了 m.put(k, v),则插入顺序不受影响。(如果在调用之前 m.put(k, v) m.containsKey(k) 会立即返回 true,则键 k 会重新插入到映射 m 中。)

英文:

By default, Maps and Sets in Scala do not give any guarantee with regards to the order in which items are returned when iterating over them one by one. The only base collection to do so is the Seq.

You can learn more about Maps in Scala here. The documentation has also a page describing several concrete implementations of the Map trait which can suit you:

ListMap was also mentioned in a comment and you can use it as in the following example.

import scala.collection.immutable.ListMap

val seq = Seq("Test" -> 1, "Test2" -> 2, "Test3" -> 3)

seq.to(ListMap).foreach(println)

/* prints:
 *
 * ```
 * (Test,1)
 * (Test2,2)
 * (Test3,3)
 * ```
 */

You can play around with this code here on Scastie.

Expanding on that, note however that certain operations scale badly for this type, as explained in the documentation:

> Entries are stored internally in reversed insertion order, which means the newest key is at the head of the list. As such, methods such as head and tail are O(n), while last and init are O(1). Other operations, such as inserting or removing entries, are also O(n), which makes this collection suitable only for a small number of elements.

If apart from insertion order you might be able to rely on some form ordering (e.g. the lexicographical order of the keys), you can use a SortedMap as well.

If you are open to using a mutable data structure, Scala also has its own LinkedHashMap (another one suggested in a comment above):

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

Finally, you can also use Java's LinkedHashMap:

> Hash table and linked list implementation of the Map interface, with predictable iteration order. This implementation differs from HashMap in that it maintains a doubly-linked list running through all of its entries. This linked list defines the iteration ordering, which is normally the order in which keys were inserted into the map (insertion-order). Note that insertion order is not affected if a key is re-inserted into the map. (A key k is reinserted into a map m if m.put(k, v) is invoked when m.containsKey(k) would return true immediately prior to the invocation.)

huangapple
  • 本文由 发表于 2023年6月12日 00:12:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/76451354.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定