I started reading C# in depth. Now I'm in the journey of Generics. I came across the first example of Generics in this book as:
static Dictionary<string,int> CountWords(string text)
{
Dictionary<string,int> frequencies;
frequencies = new Dictionary<string,int>();
... //other code goes here..
And after this code, author says that:
The CountWords method first creates an empty map from string to int
This looks vague to me, as a novice in C#, what the author is trying to mean string to int(in the above statement)? I'm bit confused with this line.
Thanks in advance.
Lets say we want to count the words in a paragraph:
I started reading C# in depth. Now I am in the journey of Generics.
I came across the first example of Generics in this book as
In order to count the words, you'll need some data structure that will be able to store a number of occurrences for each of the words, that will basically attach a number to a string, like
I - 3 times
in - 3 times
Generics - 2 times
etc...
that structure maps a string to an integer, and in C# Generics, that structure is a Dictionary<string,int>
BTW, if you are a C# beginner, i would recommend against C# in depth, which, while being a great book, assumes a quite advanced reader.
He means that string is your key and int is the value paired with the key.
Dictionary<string,int> maps a string key (or lookup) to an int value.
Consider Dictionary<string,int> frequencies.
When you try to add an item you use (for example)
frequencies.Add("key3", 3)
When you add another item you cannot repeat "key3", because in Dictionary that's a unique key; so you create a "map" because you are sure you have unique keys and you can recall values using their key: frequencies["key3"]...
Dictionary<string, int> frequencies = new Dictionary<string, int>();
frequencies.Add("key3", 3);
frequencies.Add("key4", 4);
frequencies.Add("key3", 5); // This raises an error
int value = frequencies["key3"];
This function counts all words in a given string. In the returned dictionary exist for every found word one entry with the word as key. In the int value is stored, how many times this word was found in the string.
It means from the Key to the Value
Related
The dificulty I'm facing is as follows:
I need to create a dictionary with something like 10 main definitions in it. What I actually need is to be able to recognize some X amount of strings that should represent one certain string. I want to have like 10 main strings and to be able to add different representative string to each one of them. Example: I have the strings "animal", "fruit" and "object" and I want to assing e.g. the strings "dog", "cat" and "snake" to the string "animal". The point is that everytime I face one of those strings, I'll want replace it with "animal".
I imagine this as some kind of dictionary and I've read the documentary about this class in c#, but I'm not quite sure it's the best method so that's why I'm asking you. My idea was to create a new entry each time I face one of the substrings and to set that substring (e.g. "dog") as a key with value - the main string (in this case "animal"), but I find it quite inappropriate.
Following question - could you suggest a good enough method to store the data from that "dictionary" locally/online, so that I can collect data troughout the time I'm using my code.
Thanks a lot, friendly members of this community! :D
What would be best in your case would be to inverse your logic. You should use a Dictionary with a string a key and List as value and retrieve the value using the key which is a member of your list.
var d = new Dictionary<string,List<string>>();
d.Add("Animal", new List("Dog","Cat");
d.FirstOrDefault(x => x.Value.Contains("Cat")).Key;
If I understand correctly, you can just use a dictionary:
var d = new Dictionary();
d.Add("dog", "animal");
....
d["dog"]; //this gives you animal.
You can do this with each item you want to replace, and the dictionary will give you its replacement value.
I wanted to ask if there is a way to transform a String into a arrayname?
Example:
I got like 4 arrays:
name,age,gender,nationality
and now i got a String which says "nationality" now i want in my code that i can use that String to access the nationality array. Or if i change the String to "age" i want to access the age array... i hope its clear what i mean.
I dont really know how this could be done and hope you could atleast give me input where to find some informations to this topic.
Hopefully someone can help me!
Greetings from Germany,
Marvin
edit:
Thanks for all the answers.. I'm not really well in programming till now so im not sure if i understood everything right.
I guess it doesnt really matter if i do everything with String or have different types in the array because i could convert them or?
I have never worked with Lists till now. And i guess my examople maybe wasnt the best so here is a new one:
I got different array (lets say all String):
I make this Programm for a tabletopgame
name //Name of a hero
points // Costs for using it
leader //kinda the fraction
character //an attribut units got
abilityhelpers //what does a hero need to be helpfull for this unit
where //where to serach
So i got different units:
pete
10
leader a
friendly
less 100 //so every hero that costs less then 100 points helps him
points
mike
110
leader b
smart
leader a //so he is good with heros from leader a
leader
The Programm picks random one unit, lets say it picks Mike... no it look what Abilityhelpers he got... and in this case its "leader a" so he should go through all entries in the array Leader and add every hero that got "leader a" to a list.
Then it picks a random one of this list and does the same for him... so if Pete is picked it searches in the array Points for everyone who got less then 100 points.
But i dont want like 1 million if cases for the different posibillities ( there are 8 different attributes and sometimes there are 3 of them as restrictions for a good match (like: leader a, friendly, points less then 5))
I would like to have something like:
String a = where [0]; //a string that contains the information where to search for the helper
for(i=0;1<array.length;i++)
{
if (a[i]==abilityhelpers[0])
//then add name[i] to the list
}
I don't want the exact Code for this Problem (and guess i wouldn't get it), i would love to know if that is possible and if yes some advices where to look or some food for my thoughts^^
You can use Generic Dictionary that has key as a string and value as string array / List<string>
Dictionary<string, string[]> dictionary = Dictionary<string, string[]>();
Or
Dictionary<string, List<string>> dictionary = Dictionary<string, List<string>>();
Why don`t you store the Arrays in a Dictionary. Something like that:
Dictionary<string, Array> arrays = new Dictionary<string,Array>();
string key="key";
Array ages = arrays[key];
In case your arrays are of different types (and so you can't use Dictionary<String, T>) I suggest exploiting DataTable:
DataTable table = new DataTable();
// Age is integer: 34, 81, 19...
table.Columns.Add("Age", typeof(int));
// Nationality is String: "English", "Dutch"...
table.Columns.Add("Nationality", typeof(String));
// Gender is Char: 'M' or 'F'
table.Columns.Add("Gender", typeof(Char));
// ...
To obtain data form the table:
int[] ages = table
.AsEnumerable()
.Select(row => row["Age"])
.ToArray();
I kind of toil to describe my situation, therefore my post might geht al litle longer.
I want to search for given keys in strings. The strings are lines of a text file, the comparison is to be done as the file is beeing read line by line.
There is a class which has the properties NUMBER and TYPE among others. That are the keys for which is to be searched in the line string.
A trivial solution would be to store the class instances in a list and run through that list for each and every line and see if the line string contains the keys of the current list entry.
The performance of this implementation though would be horrible, since on the average for every line the program will loop through the entire list. This is since every key in the list occures at most one time in the file. So there are a lot of lines which don't contain a key.
I hope you guys get what I'm trying to explain and get the idea.
Example for objects:
O1:
ID - 1
NR - 1587
TYPE - COMPUTER
O2:
ID - 2
NR - 5487
TYPE - TV
text file lines:
bla bla \t 8745 RADIO
fsdakfjd9 9094km d9943
dkjd894 4003p \t 5487 TV
sdj99 43s39 kljljkljfsd
...
On line 3 the program should find the match and save the ID 2 together with the line content.
Thanks for any input ...
Toby
Looking up strings in your file is intensive so ideally, you only want to do this once.
I think it's ideal if you store class references in a Dictionary or a Hashtable.
Then you can do something like
var myDictionary = new Dictionary<string, ObjectType>();
while(string line = reader.ReadLine())
{
// Parse the possible key out of the line
if (myDictionary.ContainsKey(keyFromLine) doSomething(line, myDictionary[keyFromLine]);
}
void doSomething(string line, ObjectType instance)
{
// Unwrap the line and store appropriate values
}
Splitting, counting within strings is by nature resource and time intensive. You need parsing and searching. You have to loop through all the strings and save it, and then search it using Dictionary<key, value>. Try to loop the fewest and the way to accomplish that is by running the program on all the lines and saving it first. Don't scan lines on every search.
I have a dataset. This dataset will serve a lookup table. Given a number, I should be able to lookup a corresponding value for that number.
The dataset (let's say its CSV) has a few caveats though. Instead of:
1,ABC
2,XYZ
3,LMN
The numbers are ranges (- being "through", not minus):
1-3,ABC // 1, 2, and 3 = ABC
4-8,XYZ // 4, 5, 6, 7, 8 = XYZ
11-11,LMN // 11 = LMN
All the numbers are signed ints. No ranges overlap with another ranges. There are some gaps; there are ranges that aren't defined in the dataset (like 9 and 10 in the last snippet above).
`
How might I model this dataset in C# so that I have the most-performant lookup while keeping my in-memory footprint low?
The only option I've come up with suffers from overconsumption of memory. Let's say my dataset is:
1-2,ABC
4-6,XYZ
Then I create a Dictionary<int,string>() whose key/values are:
1/ABC
2/ABC
4/XYZ
5/XYZ
6/XYZ
Now I have hash performance-lookup, but tons of wasted space in the hash table.
Any ideas? Maybe just use PLINQ instead and hope for good performance? ;)
If your dictionary is going to truly store a wide range of key values, an approach that expands all possible ranges into explicit keys will rapidly consume more memory than you likely have available.
You're best option is to use a data structure that supports some variation of binary search (or other O(log N) lookup technique). Here's a link to a generic RangeDictionary for .NET that uses an OrderedList internally, and has O(log N) performance.
Achieving constant-time O(1) lookup requires that you expand all ranges into explicit keys. This requires both a lot of memory, and can actually degrade performance when you need to split or insert a new range. This probably isn't what you want.
You can create a doubly-indirected lookup:
Dictionary<int, int> keys;
Dictionary<int, string> values;
Then store the data like this:
keys.Add(1, 1);
keys.Add(2, 1);
keys.Add(3, 1);
//...
keys.Add(11, 3);
values.Add(1, "ABC");
//...
values.Add(3, "LMN");
And then look the data up:
return values[keys[3]]; //returns "ABC"
I'm not sure how much memory footprint this will save with trivial strings, but once you get beyond "ABC" it should help.
EDIT
After Dan Tao's comment below, I went back and checked on what he was asking about. The following code:
var abc = "ABC";
var def = "ABC";
Console.WriteLine(ReferenceEquals(abc, def));
will write "True" to the console. Which means that the either the compiler or the runtime (clarification?) is maintaining the reference to "ABC", and assigns it as the value of both variables.
After reading up some more on Interned strings, if you're using string literals to populate the dictionary, or Interning computed strings, it will in fact take more space to implement my suggestion than the original dictionary would have taken. If you're not using Interned strings, then my solution should take less space.
FINAL EDIT
If you're treating your strings correctly, there should be no excess memory usage from the original Dictionary<int, string> because you can assign them to a variable and then assign that reference as the value (or, if you need to, because you can Intern them)
Just make sure your assignment code includes an intermediate variable assignment:
while (thereAreStringsLeftToAssign)
{
var theString = theStringToAssign;
foreach (var i in range)
{
strings.Add(i, theString);
}
}
As arootbeer has mentioned in his answer, the following code does not create multiple instances of the string "ABC"; rather, it interns a single instance and assigns a reference to that instance to each KeyValuePair<int, string> in dictionary:
var dictionary = new Dictionary<int, string>();
dictionary[0] = "ABC";
dictionary[1] = "ABC";
dictionary[2] = "ABC";
// etc.
OK, so in the case of string literals, you're only using one string instance per range of keys. Is there a scenario where this wouldn't be the case--that is, where you would be using a separate string instance for each key within the range (this is what I assume you're concerned about when you speak of "overconsumption of memory")?
Honestly, I don't think so. There are scenarios where multiple equivalent string instances may be created without the benefit of interning, yes. But I can't imagine these scenarios would affect what you're trying to do here.
My reasoning is this: you want to assign certain values to different ranges of keys, right? So any time you are defining a key-range-value pairing of this sort, you have a single value and several keys. The single part is what leads me to doubt that you'll ever have multiple instances of the same string, unless it is defined as the value for more than one range.
To illustrate: yes, the following code will instantiate two identical strings:
string x = "ABC";
Console.Write("Type 'ABC' and press Enter: ");
string y = Console.ReadLine();
Console.WriteLine(Equals(x, y));
Console.WriteLine(ReferenceEquals(x, y));
The above program, assuming the user follows instructions and types "ABC," outputs True, then False. So you might think, "Ah, so when a string is only provided at run-time, it isn't interned! So this could be where my values could be duplicated!"
But... again: I don't think so. It all comes back to the fact that you are going to be assigning a single value to a range of keys. So let's say your values come from user input; then your code would look something like this:
var dictionary = new Dictionary<int, string>();
int start, count;
GetRange(out start, out count);
string value = GetValue();
foreach (int key in Enumerable.Range(start, count))
{
// Look, you're using the same string instance to assign
// to each key... how could it be otherwise?
dictionary[key] = value;
}
Now, if you were actually thinking more along the lines of what LBushkin mentions in his answer--that you may potentially have huge ranges, making it impractical to define a KeyValuePair<int, string> for each key within that range (e.g., if you have a range of 1-1000000)--then I would agree that you're best off with some sort of data structure that bases its lookup on a binary search. If that's more your scenario, say so and I will be happy to offer more ideas on that front. (Or you could just take a look at the link LBushkin already posted.)
Use a balanced ordered tree (or something similar) mapping start-of-range to end-of-range and data. This will be easy to implement for non-overlapping ranges.
arootbeer has a good solution, but one you may find confusing to work with.
Another choice is to use a reference type instead of a string, so that you point to the same reference
class StringContainer {
public string Value { get; set; }
}
Dictionary<int, StringContainer> values;
var value1 = new StringContainer { Value = "ABC" };
values.Add(1, value1);
values.Add(2, value1);
They will both point to the same instance of StringContainer
EDIT: Thanks for the comments everyone. This method handles value types other than string, so it might be useful for more than the given example. Also, it is my understanding that strings don't always behave in the manner you would expect from reference values, but I could be wrong.
This might be a very silly / stupid question, but, my defence is that I am a beginner!
Suppose I have a dictionary in c# :
Dictionary<int,string> D = new Dictionary<int,string>();
If I wanted to add all values (which is string) instead of looping and appending all values to a stringBuilder, i do:
string.Join(",",D.values.ToArray());
which works fine. Now, If I want to add all the keys (which is int) to a total, is there a similar way to do this? I dont want to loop through (unless that is the only way) each item and add them. I am not talking about D.Add() which adds a new item, but Math addition, like Key 1 + key 2 etc..
Thanks!
D.Keys.Sum();
will do just what you think it should
By its very definition, adding together numbers requires that you "loop through each one of them".
var total = D.Keys.Sum()
int x = D.Keys.Sum(); or D.Keys.ToList<int>().Sum()
actually you dont need to use to list at all