33

I have objects called Country. At some point in the program, I want to set the field power of each object.

The power for each country is fixed and I have data for all 196 countries here on a piece of paper. My code should check, for instance, if the country's name is USA (and if so, set its power to 100) and so on.

I know I can do it with a switch-case, but what is the best, nicest, and most efficient way to do it?

APerson
  • 8,140
  • 8
  • 35
  • 49
nasim
  • 725
  • 2
  • 8
  • 17
  • 43
    Use a `Dictionary` as a lookup table. – D Stanley Dec 17 '14 at 15:28
  • 9
    I don't think the switch statement would be that big. `switch (country) { case "USA": return 100; default: return 0; }` – user2023861 Dec 17 '14 at 20:16
  • 1
    fubo: Sorry for the nitpick, but you're mistaking countries and states. Countries are geographical units, and don't have power... More to the point, note that since you have many countries, _subclassing_ (i.e. inheriting Country by other classes) is not an option. But if you had just several possible values, you could have class Country::Weak, class Country::Medium, class Country::Strong, each with their own constant value for power. – einpoklum Dec 17 '14 at 22:34
  • Thanks for your comment :) In my code they are called players, I wrote countries here so that people who read would get a better sense! – nasim Dec 17 '14 at 22:39
  • You can make a trie. – user541686 Dec 18 '14 at 12:01

6 Answers6

54

You can store country-power pairs into a Dictionary<string, int> then just get the score of a particular country by using indexer:

var points = new Dictionary<string,int>();
// populate the dictionary...
var usa = points["USA"];

Edit: As suggested in comments you should store the information in external file, for example an xml would be a good choice. That way you don't have to modify the code to add or remove countries. You just need to store them into XML file, edit it whenever you need.Then parse it when your program starts, and load the values into Dictionary.You can use LINQ to XML for that.If you haven't use it before there are good examples in the documentation to get you started.

Selman Genç
  • 100,147
  • 13
  • 119
  • 184
  • 11
    I would recommend storing the data in a file or database, i.e. not in the code! The amount of 196 datasets is definitely not well-suited for hardcoding. – ComFreek Dec 17 '14 at 18:38
  • 5
    to add to what @ComFreek said, JSON would be well suited and is a nice portable format with existing ways of easily parsing into a Dictionary. – Brad Allred Dec 17 '14 at 21:20
  • 1
    A very simple way to read a file could be: `var dict = System.IO.File.ReadLines(@"C:\path\file.extension").Select(line => line.Split(',')).ToDictionary(arr => arr[0], arr => int.Parse(arr[1]));` which assumes that it is comma separated text format (like a `.csv` file) with no blank lines. Exceptions could arise in a lot of situations, of course. If it needs to be more robust, certainly choose an XML scheme as suggested in the last section of the question. – Jeppe Stig Nielsen Dec 18 '14 at 13:56
  • 3
    To people advocating an external file: KISS, YAGNI! OP told us that "the power of each country is fixed". Hardcoding is a good solution, which can easily be refined if needed. Of course, requirements may change, but maybe not. Look at the added complexity of managing external resources: file is missing, badly encoded, corrupted; now deal with exceptions, log errors, inform user. Furthermore, a simple switch is sufficient: the compiler would generate a dictionary anyway (see my answer). – coredump Dec 18 '14 at 16:21
  • @coredump and a further comment was added stating "In my code they are called players, I wrote countries here so that people who read would get a better sense" so there's no guarantee that it will be fixed to 196 - by most tallies there are 209 countries, or 193 UN Member States, 2 Observers and 11 "Others" – Zhaph - Ben Duguid Dec 19 '14 at 12:16
  • @coredump - the number of countries is fixed, and there will be no new taxes. Also, he never said the power of each country was fixed. And games have expansion packs... – Peter Wone Dec 19 '14 at 14:07
24

Whilst Selmans answer is right and good, it does not answer how to actually populate the Dictionary. Here is it:

var map = new Dictionary<string, int> {
    {"USA", 100},
    {"Germany", 110}
};

you may however also just add it as follows:

map.Add("USA", 100);
map.Add("Germany", 110);

Now you may access the value (as already mentioned by Semans):

map["USA"] = 50;        // set new value for USA
int power = map["USA"]; // get new value

EDIT: As already mentioned within comments and other answers you may of course store the data within an external file or any other data-storage. Having said this you may just initialize an empty dictionary and then fill it with the Add-method previously mentioned for every record within that storage.

MakePeaceGreatAgain
  • 35,491
  • 6
  • 60
  • 111
  • 1
    `+1` good example because I like the way it displays to `nasim` how to load / populate / and Access the Dictionary<> object – MethodMan Dec 17 '14 at 15:47
  • 5
    If this list ever changes and you want it maintained without using up a developer's time, you should load the values from an easy-to-edit config file. – Keen Dec 17 '14 at 18:52
  • 1
    I'd probably code in a simple config menu that uses a GridView so the user can make changes within the program instead of notepad. – Lee Harrison Dec 17 '14 at 22:00
  • 6
    @Cory - A config file can be a great thing, so I'm not exactly disagreeing with you, but I can't resist pointing out the opposite possibility: if the list isn't likely to change often, it might use up more of the developer's time to decide on a file format, write code to parse the file, handle "file not found" or parsing errors, fix bugs, ... :-) – antinome Dec 18 '14 at 00:02
  • 1
    @antinome - That's a valid point, but I'm yet to come across a programming language which can't build a dictionary from a JSON file in a few lines at most. – sapi Dec 18 '14 at 01:22
  • 1
    @antinome Yes, we're in perfect agreement since we both hinge this choice on the likelihood for the list values to change. It's ultimately up to the OP to decide what they need, and all of this is good to have in mind. – Keen Dec 18 '14 at 18:01
6

This is the right question to begin with, but there are a lot of things you need to learn. Many folk have given you answers to the question you asked. I'm going to be annoyingly Zen and tell you to unask the question because there is a larger problem to resolve.

Instead of hard coding this, store the related properties in an n-tuple also known as a database row and use a database engine to manage the relation between the two. And then since you are using C# it would probably be smart to learn to use LINQ. But before you do that, learn a bit of data modelling theory, because data-modelling is what you are doing.

Peter Wone
  • 17,965
  • 12
  • 82
  • 134
  • 3
    "When your only tool is a hammer, everything looks like a nail." Introducing a database seems like serious overkill for this problem. But I agree with the answers suggesting loading the data from a file rather than hard-coding it. – Ian Goldby Dec 18 '14 at 09:30
  • 2
    Wow!! Thank you all for all of these solutions. There is definitely a lot for me to learn! Until a month ago, my only tool was array, so even dictionary is a an upgrade for me!! :D But I am learning fast, thanks to you guys – nasim Dec 18 '14 at 16:06
  • 1
    I would remove the talk about the "above" answers. Answers can be sorted in multiple ways. Instead, just say what you actually mean. "The answers that tell you how to hard code countries are not doing you any favours in the long run." – MiniRagnarok Dec 18 '14 at 16:19
  • @MiniRagnarok I agree, but I'm making two points. One is architectural, the other is about deep vs shallow teaching. I'll reword it slightly. – Peter Wone Dec 18 '14 at 22:32
  • @IanGoldby - Linq2Xml operates on XML that can be directly loaded in a single file operation. It's still a database, it's even updatable. I therefore reject your assertion that a database is overkill. – Peter Wone Dec 18 '14 at 22:47
  • @PeterWone There are many other ways of loading a simple key-value data file with a single library call that require far less overhead than LINQ etc. My point is to use the right tool for the job. If the application was *already* a database application then I would have no issue with adding a new table to hold this new configuration data. Databases have their uses, but there is no such thing as a golden hammer. – Ian Goldby Dec 19 '14 at 08:42
  • 1
    @IanGoldby - the right tool is the one with the lowest TCO. Cost to write, cost to debug, cost to maintain, for data manipulation all are lower with databases because structured data manipulation is a solved problem. Stop re-inventing the wheel. – Peter Wone Dec 19 '14 at 14:19
2

Since you said you have "objects" called "Country", and you have tagged your question "C#", it would seem that you have two forces at work in your code. One is that having to refer to a map, however efficiently implemented, is not as cheap as referring to a member variable. On the other hand there might be some benefit to a setup where all the attributes of a country can be found in the same place as the attributes of other countries (the map-oriented solutions do address this concern). But these forces can be reconciled something like this:

class Country { // Apologies that this sketch is more C++ than C#
public:
   Country(string name_, int power_);
private:
   string name;
   int power;
};
void MakeCountries()
{
    countries.Add(new Country("USA", 50));
    countries.Add(new Country("Germany", 60));
    // ....
}
cardiff space man
  • 1,442
  • 14
  • 31
2

Do you need to update your data at runtime?

Community
  • 1
  • 1
coredump
  • 37,664
  • 5
  • 43
  • 77
  • For the "Yes?" question I agree with your answer, for "No? Use a switch" not. A **switch statement over 196 countries** (Nasim mentioned the amount of data), is not a good practice in my opinion. – Matt Feb 22 '18 at 12:26
0

What about making an array of Strings for storing country names in ascending order of their power. It will be more simple to implement.Then the index of each country can represent its power. This is possible, only if the power is continues counting numbers.

If its not , another siple way is to implement them as linked list. So that u will be able to change if u want. A list with 2 fields; 1for the country and other for the power