Using a String to decide which Array to use (c#) - c#

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();

Related

C# how can I write data from a two-dimensional array to a text-file and format them in columns?

So I have a two-dimensional array and I want to write all data to a text-file. But I want them to appear in columns in the text-file.
(I haven't declared them like this in my code, but I think this is what the array would look like written out):
myArray = [{Jamie, 5}, {Susan, 7}, {Robert, 2}, {Sam, 9}];
I want in the text-file it to look like this:
Jamie 5
Susan 7
Robert 2
Sam 9
I have looked at other answers such as How to write contents of an array to a text file? C# and Format a string into columns but I feel like they are only answering half of my question, and I don't understand them either.
What I have so far is:
using (StreamWriter sw = new StreamWriter(#"../../test.txt", false))
{
foreach ()
{
}
}
I'm not sure what I am supposed to have in foreach().
How do I do this?
One easy way is to:
Iterate all strings you need to output and store the length of the longest one.
Iterate again all items; using two nested loop (rows and columns) seems like a good idea.
Write each item you iterate in step 2 padded to the right with enough whitespaces to account for column spacing and the longest length of step 1. string.PadRight seems like a good option.
You are done.
Of couse yo can get fancier and store the longest length of each column and then pad each column with it's specific length...

Best way to create and store a categorized dictionary

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.

Calculating numbers from an external file from my project (Project Euler #13)

I'm trying to find multiple ways to solve Project Euler's problem #13. I've already got it solved two different ways, but what I am trying to do this time is to have my solution read from a text file that contains all of the numbers, from there it converts it and adds the column numbers farthest to the right. I also want to solve this problem in a way such that if we were to add new numbers to our list, the list can contain any amount of rows or columns, so it's length is not predefined (non array? I'm not sure if a jagged array would apply properly here since it can't be predefined).
So far I've got:
static void Main(string[] args)
{
List<int> sum = new List<int>();
string bigIntFile = #"C:\Users\Justin\Desktop\BigNumbers.txt";
string result;
StreamReader streamReader = new StreamReader(bigIntFile);
while ((result = streamReader.ReadLine()) != null)
{
for (int i = 0; i < result.Length; i++)
{
int converted = Convert.ToInt32(result.Substring(i, 1));
sum.Add(converted);
}
}
}
which reads the file and converts each character from the string to a single int. I'm trying to think how I can store that int in a collection that is like 2D array, but the collection needs to be versatile and store any # of rows / columns. Any ideas on how to store these digits other than just a basic list? Is there maybe a way I can set up a list so it's like a 2D array that is not predefined? Thanks in advance!
UPDATE: Also I don't want to use "BigInteger". That'd be a little too easy to read the line, convert the string to a BigInt, store it in a BigInt list and then sum up all the integers from there.
There is no resizable 2D collection built into the .NET framework. I'd just go with the "jagged arrays" type of data structure, just with lists:
List<List<int>>
You can also vary this pattern by using an array for each row:
List<int[]>
If you want to read the file a little simpler, here is how:
List<int[]> numbers =
File.EnumerateLines(path)
.Select(lineStr => lineStr.Select(#char => #char - '0').ToArray())
.ToList();
Far less code. You can reuse a lot of built-in stuff to do basic data transformations. That gives you less code to write and to maintain. It is more extensible and it is less prone to bugs.
If you want to select a column from this structure, do it like this:
int colIndex = ...;
int[] column = numbers.Select(row => row[index]).ToArray();
You can encapsulate this line into a helper method to remove noise from your main addition algorithm.
Note, that the efficiency of all those patterns is far less than a 2D array, but in your case it is good enough.
In this case you can simply use an 2D array, since you actually do know in advance its dimensions: 100 x 50.
If for some reason you want to solve a more general problem, you may indeed use a List of Lists, List>.
having said that, I wonder: are you actually trying to sum up all the numbers? if so, I would suggest another approach: consider just which section part of the 50 digit numbers actually influences the first digits of their sum. Hint: you don't need the entire number.

Generics in C#, Dictionary<TKey,TValue>

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

Datastructures, C#: ~O(1) lookup with range keys?

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.

Categories