Reputation: 14878
I have a Map
and I want to go through both the values
and keys
and replace any occurrences of particular objects which meet some set criteria with some other objects, so if I find a key that meets a specific criteria.
I want to swap that key for a different object that still points at the same value object in the map, similarly if I find a value that I want to replace I want the original key to point at the replacement value.
Here is some code that works for a simplified example but it looks quite ugly, is there a nicer way of achieving this, meaning a method which doesn't require that you extract every key and value you want to replace and then write the replacements back in.
It would be nicer to be able to just iterate of the map once rather than iterating over the keys, and then iterating over all the keys and values to be replaced?
void main(){
//replace all values of instance A with an Object and all keys starting with "t" with the same key minus the "t"
var m = {
"one": new A(),
"two": new A(),
"three": new B(),
"four": new B()
};
mapKeyAndValueSwapper(m,
keyMeetsCondition: (k) => k.startsWith("t"),
valueMeetsCondition: (v) => v is A,
keyReplacer: (k) => k.replaceFirst("t", ""),
valueReplacer: (v) => new Object());
print(m);
}
mapKeyAndValueSwapper(Map m, {bool keyMeetsCondition(key), bool valueMeetsCondition(value), dynamic keyReplacer(key), dynamic valueReplacer(value)}){
var keysToReplace = [];
var keysToReplaceValuesFor = [];
var keys = m.keys;
keys.forEach((k){
if(keyMeetsCondition != null){
if(keyMeetsCondition(k)){
keysToReplace.add(k);
}
}
if(valueMeetsCondition != null){
if(valueMeetsCondition(m[k])){
keysToReplaceValuesFor.add(k);
}
}
});
keysToReplaceValuesFor.forEach((k){
m[k] = valueReplacer(m[k]);
});
keysToReplace.forEach((k){
m[keyReplacer(k)] = m.remove(k);
});
}
class A{}
class B{}
Upvotes: 4
Views: 9232
Reputation: 274
You can create an extension on Map that creates a list from the mapEntries and then manipulate that list to update the key (using the index to maintain order), then clear the map and rebuild it from your updated list.
extension MapX<K, V> on Map<K, V> {
bool updateKey({required K currentKey, required K newKey}) {
if (containsKey(currentKey) && !containsKey(newKey)) {
final value = this[currentKey] as V;
final index = keys.toList().indexWhere((k) => k == currentKey);
final mapEntriesList = entries.toList();
mapEntriesList.removeAt(index);
mapEntriesList.insert(index, MapEntry<K,V>(newKey, value));
clear();
addEntries(mapEntriesList);
return true;
} else {
return false;
}
}
}
Upvotes: 2
Reputation: 657496
I think this does the same:
Map newMap = {};
m.forEach((k, v) {
var key = k;
var value = v;
if(m[k] is A) {
value = new Object();
}
if(k.startsWith('t')) {
key = k.replaceFirst('t', '');
}
newMap[key]=value;
});
Upvotes: 5