How to initialize an array constant specifying desired indexes - c#

What I just want is to initialize a string[] array constant by specifying not only the values, but the indexes they will be attached to.
For example, on:
private static readonly string[] Pets = new string[] {"Bulldog", "GreyHound"};
I would like to state that BullDog corresponds to index 29 and GreyHound to 5 (Like php :) )
Any suggestion?
Cheers,

If you have some flexibility in terms of your data structure, it would be more efficient to use a Dictionary<int, string> instead of an array for this behavior.
Example (if you are using C# 3 or above):
var pets = new Dictionary<int, string> {
{ 29, "Bulldog" },
{ 5, "Greyhound" }
};
Console.WriteLine(pets[5]);
Same example for legacy applications:
Dictionary<int, string> pets = new Dictionary<int, string>();
pets[29] = "Bulldog";
pets[5] = "Greyhound";
Console.WriteLine(pets[5]);

It sounds like you don't want an array, but a Dictionary<int, string> instead, which could be initialized like this:
private static readonly Dictionary<int, string> pets =
new Dictionary<int, string> {
{ 29, "Bulldog" },
{ 5, "Greyhound" }
};
(Note that this collection initializer syntax was only added in C# 3. If you're using an older version you'll have to call Add or the indexer explicitly multiple times.)
You can access a dictionary via its indexer which looks like array access:
string x = pets[29];
pets[10] = "Goldfish";

I don't think what you want is possible in C# when declaring arrays.
Besides using a Dictionary as others have suggested, you could try using an enumeration instead, with values corresponding to your specific array indices and descriptions (using the Description attribute) corresponding to the string values.
private enum Pets
{
[Description("GreyHound")]
Greyhound = 5,
[Description("Bulldog")]
Bulldog = 29
}

For the record, I agree with everyone that a Dictionary is probably more appropriate. But you can write a little method to pull off what you want:
public static T[] CreateArray<T>(params Tuple<int, T>[] values)
{
var sortedValues = values.OrderBy(t => t.Item1);
T[] array = new T[sortedValues.Last().Item1 + 1];
foreach(var value in sortedValues)
{
array[value.Item1] = value.Item2;
}
return array;
}
And call it like this:
string[] myArray = CreateArray(new Tuple<int, string>(34, "cat"), new Tuple<int, string>(12, "dog"));
If C# receives the syntactic sugar for Tuple that many people seem to want, this would get a tad cleaner looking.
Is this a good idea? Almost certainly not, but I'll leave that for the OP to judge.

You can not do that in the initializer, you need to first specify the size of the array and then add items at specific locations.
private static readonly string[] Pets = new string[42];
and then in a static constructor you insert your items.
private static MyClass
{
Pets[29] = "Bulldog";
Pets[5] = "Greyhound";
}
But as other have suggested: use the Dictionary<int, string>.

You don't need a string array, but instead a Dictionary.
Take a look at link text, there's a fine example there (which I adapted here):
Dictionary<int, string> d = new Dictionary<int, string>();
d.Add(2, "cat");
d.Add(1, "dog");
d.Add(0, "llama");
d.Add(-1, "iguana");

Related

How can I map multipul lists to one key on C#?

I need to map one string (sentence) in to two lists (similar sentences indexes and the different word in each one).
By using "Dictionary" I have to use 2 dictionaries to save each list.
Is there other way to save a string as a key to int[] and string[]?
this is how it lookes now:
Dictionary<string, int[]> similarSentences = new Dictionary<string, int[]>();
Dictionary<string, string[]> changes = new Dictionary<string, string[]>();
I want someting like this:
Dictionary<string, int[],string[]> similarSentencesAndChanges = new Dictionary<string, int[],string[]>();
Thank you!
You could use tuples:
Dictionary<string,(int[] Similar, string[] Changes)> similarSentencesAndChanges = new Dictionary<string,(int[] Similar, string[] Changes)>();
and then you can access it like this:
var someKey = "somekey";
(int[] similar, string[] changes) = similarSentencesAndChanges[someKey];
However, depending on what you plan to do, randomly using tuples is a bad practice and you'd be wise in creating a class that contains both collections.
class SentenceData
{
public int[] Similar {get;}
public string[] Changes {get;}
}
Then, make your dictionary of type Dictionary<string, SentenceData>.
This has the added benefit of allowing the reuse of the object in other parts of your code. Furthermore, adding properties to the object at a latter stage won't involve potentially rewriting large parts of your code.
Assuming you are ok to use tuples, you could create an extension method for the generic Dictionary<TKey, TValue> type, which returns a dictionary with tuple values...
public static Dictionary<TKey, (TValue, TValue2)> Combine<TKey, TValue, TValue2>(this Dictionary<TKey, TValue> a, Dictionary<TKey, TValue2> b)
{
return a.Keys.Union(b.Keys).ToDictionary(x => x, x => (
a.ContainsKey(x) ? a[x] : default,
b.ContainsKey(x) ? b[x] : default
));
}
Example usage...
var similarSentencesAndChanges = similarSentences.Combine(changes);

Dynamically create a tuple with all the same type and a known number of elements

I am looking to dynamically create tuples of a given size that have all the same type.
So if I wanted a tuple of strings of size three I would get Tuple<string, string, string>
I have tried both to pass strings into the angle brackets for Tuple like this:
string foo = "string, string, string";
Tuple<foo> testTuple = Tuple<foo>(~parameters~);
and to pass an array of types into the angle brackets like this:
List<Type> types = new List<Type>() {"".GetType(), "".GetType(), "".GetType()};
Tuple<types> testTuple = Tuple<foo>(~parameters~);
Neither one of these worked. Does anyone know how to make the described dynamic tuples?
(The reason I want to do this is to use tuples inside of a dictionary like
Dictionary<Tuple<# strings>, int> testDictionary = new Dictionary<Tuple<x # strings>, int>();
Using tuples here is more useful than HashSets because the comparison in tuples is by components instead of by reference so that if I have
Tuple<string, string> testTuple1 = new Tuple<string, string>("yes", "no");
Tuple<string, string> testTuple2 = new Tuple<string, string>("yes", "no");
Dictionary<Tuple<string, string>, string> testDictionary = new Dictionary<Tuple<string, string>, string>() {
{testTuple1, "maybe"}
};
Console.WriteLine(testDict[testTuple2]);
it writes "maybe". If you run this same test with HashSets, it throws an error. If there is a better way to accomplish this same thing, that would also be useful.)
You could do something like this using reflection:
public static object GetTuple<T>(params T[] values)
{
Type genericType = Type.GetType("System.Tuple`" + values.Length);
Type[] typeArgs = values.Select(_ => typeof(T)).ToArray();
Type specificType = genericType.MakeGenericType(typeArgs);
object[] constructorArguments = values.Cast<object>().ToArray();
return Activator.CreateInstance(specificType, constructorArguments);
}
That will give you a tuple for a variable number of elements.
"Does anyone know how to make the described dynamic tuples?"
You can just use Tuple.Create(). For a 3-tuple:
var tupleOfStrings = Tuple.Create("string1", "string2", "string3");
var tupleOfInts = Tuple.Create(1, 2, 3);
Make custom type with List<string> inside (or List<T> if you want generic solution)
Override object.Equals: Use Enumerable.SequenceEqual for inner list in your custom class
Override object.GetHashCode() in order to use your type in dictionary

Dictionary and List

I want to use the dictionary in c# combined with a list like this
Dictionary<int, List<int>> Dir = new Dictionary<int, List<int>>();
but I am having trouble with the syntax for adding the keys and values. I thought if I just did something like
Dir.Add(integer1, integer2);
it would add integer1 was the key, and integer2 as the value. Then if I wanted to add to the integer1 key I would do
Dir.Add[interger1].Add(interger3);
I had one more question, I had a foreach loop like this to display the keys
foreach (KeyValuePair<int, List<int>> k in labelsList)
{
Console.WriteLine(k.Key + " "+ k.Value);
}
it displays the keys I expected up to 7, but it doesn't display the value's I wanted it to show, it just displays
1 System.Collections.Generic.List`1[System.Int32]
2 System.Collections.Generic.List`1[System.Int32]
3 System.Collections.Generic.List`1[System.Int32]
4 System.Collections.Generic.List`1[System.Int32]
5 System.Collections.Generic.List`1[System.Int32]
6 System.Collections.Generic.List`1[System.Int32]
7 System.Collections.Generic.List`1[System.Int32]
I have any idea to use a nested foreach like
foreach (KeyValuePair<int, List<int>> k in labelsList)
{
foreach (KeyValuePair<int, List<int>> k in labelsList)
{
Console.WriteLine(k.Key + " " + k.Value);
}
}
but I am unsure of what to put inside the nested foreach to iterate through the list
You have to add the collection into the dictionary before you can start adding values to it. Here is a solution which make one lookup (compared to two if ContainsKey is used). It also adds the list if it's missing.
public class YourClass
{
private Dictionary<int, List<int>> _dictionary = new Dictionary<int, List<int>>();
public void AddItem(int key, int value)
{
List<int> values;
if (!_dictionary.TryGetValue(key, out values))
{
values = new List<int>();
_dictionary.Add(key, values);
}
values.Add(value);
}
public IEnumerable<int> GetValues(int key)
{
List<int> values;
if (!_dictionary.TryGetValue(key, out values))
{
return new int[0];
}
return values;
}
}
When you call Dir.Add(), you need to provide a reference to a List<int> object. Providing an int itself is not right. So you need something like this:
Dir.Add(integer1, new List<int>());
Then you can update that entry like this:
Dir[integer1].Add(integer2);
Dir[integer1].Add(integer3);
Alternatively, you can use the collection initializer syntax:
Dir.Add(integer1, new List<int> { integer2, integer3});
You need to add a List<int> as value. It'll work like this:
if (!Dir.ContainsKey(integer1)) {
Dir.Add(integer1, new List<int>());
}
var list = Dir[integer1];
list.Add(integer2);
First, create an entry for your key integer1, unless you have already done so:
Dir.Add(integer1, new List<int>());
Then, find the right dictionary entry, then add to its value (in this case, your list):
Dir[integer1].Add(integer2);
You will find more entire code snippets in the other answers, if that is what you are looking for.
If you want to add an item, simply use this code
(whereas dic is your Dictionary<Int32, List<Int32>>)
if (dic.ContainsKey(yourKey))
{
dic[yourKey].Add(yourInt);
} else {
dic[yourKey] = new List<int> { yourInt };
}

BinarySearch in two dimensional list

I have dimensional list:
List<List<string>> index_en_bg = new List<List<string>>();
index_en_bg.Add(new List<string>() { word1, translation1 });
index_en_bg.Add(new List<string>() { word2, translation2 });
index_en_bg.Add(new List<string>() { word3, translation3 });
I would do binary search by the first column (words), something like this:
int row = index_en_bg.BinarySearch(searchingstr);
but it works only for a one-dimensional list. How would I extend it to work for two-dimensional lists in my case? I don't want to use Dictionary class.
In this case you need to provide your own customer IComparer-implementing comparator
public class Comparer: IComparer<IList<string>>
{
public int Compare(IList<string> x, IList<string> y)
{
// base the comparison result on the first element in the respective lists
// eg basically
return x[0].CompareTo(y[0]);
}
And you'll call it like this, offering a List where only the field you're searching is filled in.
int row = index_en_bg.BinarySearch(new List<string>() {searchingstr},new Comparer());
Well as far as I understand you should use Dictionary<K,V> instead, this way:
// 1 creating the dictionary
var dic = new Dictionary<string, string>();
dic["word1"] = "translation1";
dic["word2"] = "translation2";
dic["word3"] = "translation3";
// 2 finding a translation
var trans = dic["word1"];
And Dictionary<K,V> is really performant.
But if you insist on using BinarySearch you can implement IComparer<List<string>> and pass it to the function.
As you always search using the first item of the list you could use dictionary too.
var d = Dictionary<string, List<string>>();
as answered previously it's preforms much better than List.

How can I create a list and look up a value in C#

I would like to implement some kind of a look up in C# but I am not sure how to do this.
I have a variable that can have a value of between 0 and 9. For each variable there will be a text string that goes with it.
I guess I need to set up some kind of list.
A really simple example on how I could access the list and how I could populate the list would be much appreciated.
I tried the following:
public static class RefData
{
public static Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(0, "This Text");
dict.Add(3, "That Text");
dict.Add(4, "More Text");
}
but it gives an error message saying "can't resolve symbol dict on the lines with the dict.Add
This is an answer to the updated question. The problem with your current code is that you're trying to execute statements without them being inside a method, property, constructor etc. You can't do that. There are two obvious options here. First, you can use a method to build your dictionary:
public static class RefData
{
private static readonly Dictionary<int, string> dict = BuildDictionary();
private static Dictionary<int, string> BuildDictioary()
{
Dictionary<int, string> ret = new Dictionary<int, string>();
ret.Add(0, "This Text");
ret.Add(3, "That Text");
ret.Add(4, "More Text");
return ret;
}
}
The other is to use a collection initializer if you're using C# 3 or higher:
public static class RefData
{
private static readonly Dictionary<int, string> dict =
new Dictionary<int, string>
{
{ 0, "This Text" },
{ 3, "That Text" },
{ 4, "More Text" }
};
}
Note how in both cases I've made the variable private and read-only. You should almost never expose fields publicly - particularly mutable ones. You'll probably want to provide appropriate methods which act on the dictionary - and remember that Dictionary is not thread-safe.
You're trying to put code inside of a class definition. You need to move your dict.Add() calls either in a method or a static constructor. Something like:
public static class RefData
{
public static Dictionary<int, string> dict = new Dictionary<int, string>();
static Refdata() //this could also be: public static void PopulateDictionary()
{
dict.Add(0, "This Text");
dict.Add(3, "That Text");
dict.Add(4, "More Text");
}
}
You can do that if you want to fill it with default data, I suppose, you can always add or remove keys from it later from other parts of your code, since its a public static member.
A generic dictionary. Something like:
Dictionary<int, string> dict = new Dictionary<int, string>()
The first type, int is your key. Each key has to be unique, and will have a string value.
If you did something like this:
dict.Add(0, "This Text");
dict.Add(3, "That Text");
dict.Add(4, "More Text");
you could look up the value like this:
string value = dict[3]; //returns "That Text"
If a key already exists in the dictionary, the add will fail. As in you can't do this twice:
dict.Add(3, "That Text");
dict.Add(3, "More Text");
As I said before, the key (in this case your int) has to be unique. You can reassign the value by doing
dict[3] = "New Text"
The great thing about a generic dictionary, is that it can hold any type you want! The definition of the dictionary is Dictionary<Tkey, TValue>, you get to specify the types, and you can set them to whatever you want.
You can use the Dictionary class in System.Collections.Generic
Dictionary<byte, string> dct = new Dictionary<byte, string>();
You can add values to the dictionary like this
dct.Add(0, "Some Value");
you can access the values in dictionary like this
string val = dct[0];
I have a variable that can have a value of between 0 and 9. For each variable there will be a text string that goes with it.
This means that you need a dictionary. You can use many specialized dictionaries in .NET. But my recommendation is to use:
Dictionary<int, string> list = new Dictionary<int, string>();
To check if the list already contains something or not, simply use:
list.ContainsKey(someIntHere);
To get the string value of the specified key, simply use:
string value = list[key];
The dictionary class is your friend here.
e.g.
var textByNumber = new Dictionary<int, string>();
textByNumber[0] = "Alice";
textByNumber[1] = "Bob";
And to retrive a value, you can go:
var text = textByNumber[1];

Categories

Resources