I have a Dictionary with some key-value pairs stored in it. My problem is that in my dictionary, I have a blank space at the start of the key name, so for accessing the value, I have to use:
Pair[" Key"];
Is there any method where I can remove the starting whitespace, so I can access the value like:
Pair["Key"]
If you have a string, you can remove leading and trailing whitespace with key.Trim() (MSDN).
If you want to trim all the keys in your dictionary, you can do this:
dictionary = dictionary.ToDictionary(x => x.Key.Trim(), x => x.Value);
This has room for failure, though, if you have 2 keys that will trim to the same value. For example, it is valid to have a dictionary with keys " key" and "key ", but if you trim them all, you'll get an ArgumentException because you'd be trying to add the same key twice ("key").
Trimming your string is enough. Besides that you can also write a custom key comparer for your dictionary instead of trimming your string everytime you add or get something to/from your dictionary.
Dictionary<string, int> dict = new Dictionary<string, int>(new Comparer());
dict.Add("aa ", 10);
int i = dict[" aa"];
public class Comparer : IEqualityComparer<string>
{
public bool Equals(string x, string y)
{
return x.Trim().Equals(y.Trim());
}
public int GetHashCode(string obj)
{
return obj.Trim().GetHashCode();
}
}
Use string.Trim method:
var key = " Key".Trim();
Pair[key];
Related
I have Dictionary that the key is an array of int, and the value is a string. How can I get the value by check if int is contained in the key array?
public static Dictionary<int[], string> MyDic = new Dictionary<int[], string>
{
{new int[]{2,25},"firstValue"},
{new int[]{3,91,315,322},"secondValue"}
};
I have :
int number=91;
string value=?;
I need the value will get "secondValue"
I think this is a bad design choice. If the numbers don't repeat between keys (as you said in your comment for the question) then just flatten the keys into a simple Dictionary<int,string>. Just have the different integers all be keys for the same strings.
For example:
Dictionary<int,string>
{
[2] = "firstValue",
[25] = "firstValue",
};
In order to not repeat the same values but as different objects you can place a reference there:
string firstValue = "firstValue";
Dictionary<int,string>
{
[2] = firstValue,
[25] = firstValue,
};
In this case changing the value's content (not for a string as it is immutable but if it was some other object) for one key will change for all.
Use contains and a foreach loop (more readable than some other solutions):
string value;
int number = 91;
foreach(KeyValuePair<int[], string> entry in MyDic)
{
if (entry.Key.Contains(number))
{
value = entry.Value;
}
}
However, maybe a dictionary isn't the right choice for this.
Check out Gilads answer for another structure that you could use
string value = MyDic.FirstOrDefault(x => x.Key.Contains(number)).Value;
? is not needed, can not apply ? operand to KeyValuePair
something like
value = MyDic.FirstOrDefault(x => x.Key.Contains(number)).Value;
will return the first occurrence or null
In the below scenario how can I handle or implement collision in C# using the Hashtable class? If the 'Key' value is same I am getting an "Argument Exception".
static void Main(string[] args)
{
Console.Write("Enter a string:");
string input = Console.ReadLine();
checkString(input);
Console.ReadLine();
}
static void checkString(string input)
{
Hashtable hashTbl = new Hashtable();
foreach(char c in input)
{
hashTbl.Add(c.GetHashCode(), c);
}
printHash(hashTbl);
}
static void printHash(Hashtable hash)
{
foreach(int key in hash.Keys)
{
Console.WriteLine("Key: {0} Value: {1}",key,hash[key]);
}
}
My Expectation:
What do I need to do in the 'Value' argument to get around the 'Collision' issue. I am trying to check if the string consists of unique characters.
It seems you are misunderstanding how the Hashtable class works (and it has been deprecated since 2005 - use Dictionary<K,V> instead, but its behavior here is identical).
It seems you're expecting it to be your job to get an object's hashcode and add it to the hashtable. It isn't. All you need to do is add the object you want to use as key (each character), and the internal implementation will extract the hashcode.
However, what you're actually doing won't work even if you added the key object yourself. You're taking an input string (say, "test"), and for each character, you're adding it to the hashtable as a key. But since keys are, by definition, unique, you'll be adding the character 't' twice (it shows up twice in the input), so you'll get an exception.
I am trying to check if the string consists of unique characters.
Then you need keys only without values, that's what HashSet<T> is for.
var chars = new HashSet<char>();
foreach (char c in input)
{
if (chars.Contains(c))
{
// c is not unique
}
else
{
chars.Add(c);
}
}
But I'd prefer usin LINQ in this case:
var hasUniqueChars = input.Length == input.Distinct().Count();
As previously stated you should probably switch to the Dictionary<TKey, TValue> class for this.
If you want to get around the collission issue, then you have to check the key for existence.
Dictionary<string, object> dictValues = new Dictionary<string, object>();
Then you can use check for collission:
if (dictValues.ContainsKey(YourKey))
{
/* ... your collission handling here ... */
}
else
{
// No collission
}
Another possibility would be, if you are not interested in preserving previous values for the same key:
dictValues[YourKey] = YourValue;
This will add the key entry if it is not there already. If it is, it will overwrite its value with the given input.
I am wondering how I could replace int values in a dictionary in C#.
The values would look something like this.
25,12
24,35
12,34
34,12
I was wondering how I could only replace one line. For example if I wanted to replace the first line with a new value of 12,12. And it wouldn't replace any of the other '12' values in the dictionary.
A Dictionary<TInt, TValue> makes use of what are known as indexers. In this case, these are used to access elements in the dictionary by key, hence:
dict[25] would return 12.
Now, according to what you want to do is to have a key of 12 and a value of 12. Unfortunately, you cannot replace entries in a dictionary by key, so what you must do is:
if(dict.ContainsKey(25))
{
dict.Remove(25);
}
if(!dict.ContainsKey(12))
{
dict.Add(12, 12);
}
Note: In the values you supplied, there is already a key-value pair with 12 as its key, so you would not be allowed to add 12,12 to the dictionary as if(!dict.ContainsKey(12)) would return false.
You cannot replace the first line with 12, 12 because there is another key value pair with 12 as it's key. And you cannot have duplicate keys in a dictionary.
Anyway you may do such things like this:
Dictionary<int, int> myDictionary = new Dictionary<int, int>();
myDictionary.Add(25, 12);
myDictionary.Add(24, 35);
//remove the old item
myDictionary.Remove(25);
//add the new item
myDictionary.Add(12, 12);
EDIT: if you are going to save some x,y positions I would suggest you creating a class named Point and use a List<Point>. Here is the code:
class Point
{
public double X {get; set;}
public double Y {get; set;}
public Point(double x, double y)
{
this.X = x;
this.Y = y;
}
}
Then:
List<Point> myList =new List<Point>();
myList.Add(new Point(25, 13));
In Dictionaries, the keys must be unique.
In case the key need not be unique, you could use a List<Tuple<int, int>> or List<CustomClass> with CustomClass containing two integer fields. Then you may add or replace the way you want.
How can I convert a Key (Key in KeyEventArgs) to a string.
For example, if the user enter "-" :
e.Key.ToString() = "Subtract"
new KeyConverter().ConvertToString(e.Key) = "Subtract"
What I want is to get "-" for result, not "Substract"...
Use a Dictionary<TKey, TValue>:
Class-level:
private readonly Dictionary<string, string> operations = new Dictionary<string, string>;
public ClassName() {
// put in constructor...
operations.Add("Subtract", "-");
// etc.
}
In your method, just use operations[e.Key.ToString()] instead.
Edit: Actually, for more efficiency:
private readonly Dictionary<System.Windows.Input.Key, char> operations = new Dictionary<System.Windows.Input.Key, char>;
public ClassName() {
// put in constructor...
operations.Add(System.Windows.Input.Key.Subtract, '-');
// etc.
}
In your method, just use operations[e.Key] instead.
The post generates "Subtract" because Key returns a KeyCode, an enumeration, of which Subtract is a member.
Without an explicit mapping, there is no way to get an "-" out of that. (For an explicit mapping, use a switch, if/else, Dictionary, or whatever you like :-)
To get a character and not a key code, perhaps use a different event?
Happy coding
Well, you can use a cast if you want to convert a Keys object to a string object, like this:
string key = ((char)e.Key).ToString();
Just remember that a Keys object can accept a char cast, so we can cast the resultant char object to a string object.
If you want just to append it to a char object, just remove that crap, and make it like this:
char key = (char)e.key;
You could use a function like this:
public static string KeycodeToChar(int keyCode)
{
Keys key = (Keys)keyCode;
switch (key)
{
case Keys.Add:
return "+";
case Keys.Subtract:
return "-"; //etc...
default:
return key.ToString();
}
}
You can use the Description attributes and then override ToString() to get "-" instead of the name. Here is an article that explains how to do it http://blogs.msdn.com/b/abhinaba/archive/2005/10/20/c-enum-and-overriding-tostring-on-it.aspx
I am having difficulties to use my custom IComparer for my SortedDictionary<>. The goal is to put email addresses in a specific format (firstnam.lastname#domain.com) as the key, and sort by last name.
When I do something like this:
public class Program
{
public static void Main(string[] args)
{
SortedDictionary<string, string> list = new SortedDictionary<string, string>(new SortEmailComparer());
list.Add("a.johansson#domain.com", "value1");
list.Add("b.johansson#domain.com", "value2");
foreach (KeyValuePair<string, string> kvp in list)
{
Console.WriteLine(kvp.Key);
}
Console.ReadLine();
}
}
public class SortEmailComparer : IComparer<string>
{
public int Compare(string x, string y)
{
Regex regex = new Regex("\\b\\w*#\\b",
RegexOptions.IgnoreCase
| RegexOptions.CultureInvariant
| RegexOptions.IgnorePatternWhitespace
| RegexOptions.Compiled
);
string xLastname = regex.Match(x).ToString().Trim('#');
string yLastname = regex.Match(y).ToString().Trim('#');
return xLastname.CompareTo(yLastname);
}
}
I get this ArgumentException:
An entry with the same key already exists. when adding the second item.
I haven't worked with a custom IComparer for a SortedDictionary before, and I fail to see my error , what am I doing wrong?
If the 2 lastNames are equal then compare for example the whole email like:
int comp = xLastname.CompareTo(yLastname);
if (comp == 0)
return x.CompareTo(y);
return comp;
Actually, sorteddictionary comparison is also used to distinguish amongst keys* , so you must specify a complete comparison (not only your sorting strategy)
EDIT:
* I mean in sortedDictionary 2 keys are equal if Comparer gives 0
Well, I haven't taken apart your comparer - but it looks like it's just comparing by last name, and you're trying to add the same last name (johansson) twice. That should give you an ArgumentException.
What did you want to happen - and what do you want your comparer to do?
Perhaps you want to sort by last name and then first name? That way you can have two email addresses with the same last name but different first names, and have them still be in the dictionary together, ordered by first name.