erluxman
erluxman

Reputation: 19415

Dart map: Cannot retrieve item from with the same key it was added with

I have a Bank class which contains exchange rates. I can add items into the map but cannot retrieve the value with the same key I used to put inside the map.

class Bank {


  Map<Map<String, String>, double> _exchangeRates = Map();

  void addExchangeRate(String from, String to, double i) {
    _exchangeRates[{from: to}] = i;
  }

  double getExchangeRate(String from, String to) {
    return _exchangeRates[{from, to}];
  }

}

 void main(){
  Bank bank = Bank();
      bank.addExchangeRate("USD", "CHF", 2);
      bank.addExchangeRate("INR", "USD", 1 / 60);
      bank.addExchangeRate("INR", "NRS", 160/100);
      print(bank.getExchangeRate("USD","CHF"));
      print(bank.getExchangeRate("INR","USD"));
      print(bank.getExchangeRate("INR","NRS"));
}

Output :

null
null
null

Upvotes: 2

Views: 1179

Answers (3)

lrn
lrn

Reputation: 71813

As a third option, I'll suggest using a Map with a non-standard equality. That is one of the uses that the MapEquality from package collection is intended for.

import 'package:collection/collection.dart';

class Bank {
  static const _me = MapEquality();
  Map<Map<String, String>, double> _exchangeRates = 
      Map(equals: _me.equals, hashCode: _me.hash);

  void addExchangeRate(String from, String to, double i) {
    _exchangeRates[{from: to}] = i;
  }

  double getExchangeRate(String from, String to) =>
      _exchangeRates[{from: to}];
}

void main() {
  Bank bank = Bank();
  bank.addExchangeRate('USD', 'CHF', 2);
  bank.addExchangeRate('INR', 'USD', 1 / 60);
  bank.addExchangeRate('INR', 'NRS', 160 / 100);
  print(bank.getExchangeRate('USD', 'CHF'));
  print(bank.getExchangeRate('INR', 'USD'));
  print(bank.getExchangeRate('INR', 'NRS'));
}

This makes the lookup more efficient because it does hash-based lookup instead of linear search. There is still the overhead of creating a new map for each lookup.

It seems the "map" here is really just a pair. A Map is a high-cost abstraction for storing just a single pair, and it doesn't have a natural equality. The suggestion of using "$from$to" as key is better than using a key. If you need to separate the values later, you could also use a new class containing the two strings, and with an equals and hash code to match, like:

class _StringPair {
  final String first;
  final String second;
  _StringPair(this.first, this.second);
  int get hashCode => (first.hashCode * 37 + second.hashCode * 17) & 0x3FFFFFFF;
  bool operator==(Object other) => 
      other is _StringPair && first == other.first && second == other.second;
}

Then use StringPair(from,to) that as keys instead of {from: to}.

Upvotes: 2

Mehmet Esen
Mehmet Esen

Reputation: 6886

The problem is, in Dart everything is an object and the Map you are seeking for is not same Object the Map you are searching with. So you are getting null. You need advanced methods for this.

This is the solution:

import 'package:collection/collection.dart';

class Bank {
  Function equals = const MapEquality().equals;
  Map<Map<String, String>, double> _exchangeRates = Map();

  void addExchangeRate(String from, String to, double i) {
    _exchangeRates[{from: to}] = i;
  }

  double getExchangeRate(String from, String to) {
    return _exchangeRates[_exchangeRates.keys.firstWhere((entry){
      return equals(entry, {from : to});
    })];
  }
}

void main() {
  Bank bank = Bank();
  bank.addExchangeRate('USD', 'CHF', 2);
  bank.addExchangeRate('INR', 'USD', 1 / 60);
  bank.addExchangeRate('INR', 'NRS', 160 / 100);
  print(bank.getExchangeRate('USD', 'CHF'));
  print(bank.getExchangeRate('INR', 'USD'));
  print(bank.getExchangeRate('INR', 'NRS'));
}

Upvotes: 2

diegoveloper
diegoveloper

Reputation: 103541

That's because you are using objects as Keys, but when you try to retrieve the values you are creating new objects, so the result value is null.

I would use String as a Key composed by from and to values, like this:

class Bank {

  Map<String, double> _exchangeRates = Map();

  void addExchangeRate(String from, String to, double i) {
    _exchangeRates["$from$to"] = i;
  }

  double getExchangeRate(String from, String to) {
    return _exchangeRates["$from$to"];
  }

}

void main() {
Bank bank = Bank();
      bank.addExchangeRate("USD", "CHF", 2);
      bank.addExchangeRate("INR", "USD", 1 / 60);
      bank.addExchangeRate("INR", "NRS", 160/100);
      print(bank.getExchangeRate("USD","CHF"));
      print(bank.getExchangeRate("INR","USD"));
      print(bank.getExchangeRate("INR","NRS"));
}

Upvotes: 4

Related Questions