1

Let's say I have a map, for example:

Map<SObjectField, SObjectField> valueByKeyMap

Assuming neither the Map nor its contents are mutated by other activity in the system, can I rely on these two lists being identical both in content and order:

1.

List<Object> valueObjectsInKeyOrderList = new List<Object>();
for (SObjectField key : valueByKeyMap.keySet()) {
    valueObjectsInKeyOrderList.add(valueByKeyMap.get(key));
}

2.

List<Object> valueObjectList = new List<SObjectField>(valueByKeyMap.values());

... such that if I also have:

List<Object> keyObjectList = new List<SObjectField>(valueByKeyMap.keySet());

... and I were to take any arbitrary value out of keyObjectList, i.e.:

SObjectField key = keyObjectList[n];

... all three of these would always result in the same values:

SObjectField result1 = valueByKeyMap.get(key);
SObjectField result2 = valueObjectsInKeyOrderList[n];
SObjectField result3 = valueObjectList [n];

... regardless of the collection type or size?

If so, is this documented behaviour that is unlikely to change?

If not, would there be any way to produce valueObjectList without a loop which results in an identical collection to valueObjectsInKeyOrderList?

4

The order of iteration for both Map.keySet() and Map.values() are defined to be deterministic.

From the Summer '15 Release Notes, Iteration Order for Maps and Sets Is Now Predictable:

The order of elements in unordered collections (Map and Set) is now the same each time your code is run. Previously, the order of elements in unordered collections was arbitrary, and you couldn’t rely on the order of elements in maps and sets.

and from the Map documentation under values():

The order of map elements is deterministic. You can rely on the order being the same in each subsequent execution of the same code. For example, suppose the values() method returns a list containing value1 and index 0 and value2 and index 1. Subsequent runs of the same code result in those values being returned in the same order.

It's important to note that both accessors are defined to be deterministic, but the specific deterministic order is not committed. Currently, it is order of addition to the collection for both pieces. This can be see via, e.g.,

Map<String, String> m = new Map<String, String>();

m.put('1', 'a');
m.put('2', 'b');

for (String s: m.values()) {
    System.debug(s);
}

for (String s: m.keySet()) {
    System.debug(s);
}

outputting 'a', 'b', '1', '2'.

While it seems unlikely that this behavior would change such that the order of iteration would be different between the two, I don't believe it's ever explicitly guaranteed to be the same.

  • This is mostly what I am looking for, but I'm a little hazy on 'it is order of addition to the collection for both pieces' ... Let's say that the same key is put multiple times. So, for example, '1' might be the first key. But the value associated with that key changes. Will the new value be promoted to the head of the list? Or will the recycled key be demoted match the latter put? – Brian Kessler May 1 at 20:07
  • 2
    @BrianKessler I wouldn't necessarily expect the order of the set to match the order of the values. I would use one or the other. Honestly, a loop is still your best option. – sfdcfox May 1 at 21:15
  • 2
    I personally would not feel comfortable building much that relies on that level of implementation detail where Salesforce has not made public commitments about the underlying mechanics. – David Reed May 1 at 21:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.