Reputation: 3956
I have a collection of objects O
from which I want to create an (immutable) map of two features (say, O.name
and O.value
).
My best solution so far is
newHashMap(o.map[it.name -> it.value])
But this will instantiate and initialize a new HashMap
which is not acually what I want. Instead I want an immutable map without unneeded instantiation, similarly what
o.toInvertedMap[value]
returns - but this maps O
to O.value
.
Is there a method in the Xtend library to achieve what I want?
Note: to add some context to my general question above, I actually want to get a map of attribute names and values for my EMF EObject
s:
newHashMap(eObject.eClass.EAttributes.map[it.name -> eObject.eGet(it).toString])
Edit:
I just found this:
newImmutableMap(o.map[it.name -> it.value])
This seems more like what I want. Is this the "best" way to write it?
Upvotes: 3
Views: 897
Reputation: 1295
The "best" way of writing this conversion can mean a lot of different things.
Probably the most straightforward way to convert a collection of Pair
s to a regular mutable (!) map is to simply use
collection.toMap([key], [value])
(I'm not sure I fully understand the comment on @Jon's answer: "there is no extension method toMap
or toImmutableMap
for this. (there is toMap(computeKeysFunction)
, but this is not usable to convert a list of pairs to a map" – in addition to toMap(computeKeysFunction)
the IterableExtensions
also define a toMap(computeKeysFunction, computeValuesFunction)
, which can flexibly convert lists into maps, including lists of pairs.)
Now, as mentioned above, the toMap
extension method will produce a mutable map, so if you absolutely need an immutable map you have to apply an extra method, depending on what specifically you mean by "immutable map". To create what the Java Collections API calls an "unmodifiable" map, you can simply use the Map.copyOf
method. If you explicitly need a Guava ImmutableMap
(which is what CollectionLiterals.newImmutableMap
will return, though aliased as a regular Map
) you would have to use ImmutableMap.copyOf
instead:
def <K, V> Map<K, V> collectionOfPairsToRegularMap(Collection<Pair<K, V>> collection)
{
collection.toMap([key], [value])
}
def <K, V> Map<K, V> collectionOfPairsToUnmodifiableMap(Collection<Pair<K, V>> collection)
{
Map.copyOf(collection.toMap([key], [value]))
}
def <K, V> ImmutableMap<K, V> collectionOfPairsToImmutableMap(Collection<Pair<K, V>> collection)
{
ImmutableMap.copyOf(collection.toMap([key], [value]))
}
def <K, V> Map<K, V> collectionOfPairsToAliasedImmutableMap(Collection<Pair<K, V>> collection)
{
newImmutableMap(collection)
}
(If saving key strokes is a goal, you can further shorten some of the code by calling .copyOf
as an extension method.)
That all being said, there are obvious performance differences between these approaches, and some approaches will create multiple temporary maps.
On the other hand, using a Collection<Pair<K, V>>
as an intermediate may not be necessary at all (unless the data already arrives in that form). For the EAttribute
example in the question one could simply use toMap
directly:
def Map<String, String> attributes(EObject eObject)
{
eObject.eClass.EAttributes.toMap([name], [eObject.eGet(it).toString])
}
Again, if absolutely needed, this requires additional code for producing an immutable map, so the overall effort in that case would probably be similar to first converting the list of EAttribute
s to a list of Pair
s and then using newImmutableMap
.
Upvotes: 0
Reputation: 3956
The best way I have found so far is (as in the Update above):
newImmutableMap(o.map[name->value])
Upvotes: 2