I create the list like
var list = new List<KeyValuePair<string, string>>();
list.Add(new KeyValuePair<string, string>("1", "abc"));
list.Add(new KeyValuePair<string, string>("2", "def"));
list.Add(new KeyValuePair<string, string>("3", "ghi"));
How to select the value from this list.
Which means I need to pass 1 to the list and need to take the equal value "abc".How to do this? input is 1,output is abc.
It sounds like you just want:
var value = list.First(x => x.Key == input).Value;
That's if you're sure the key will be present. It's slightly trickier otherwise, partly because KeyValuePair is a struct. You'd probably want:
var pair = list.FirstOrDefault(x => x.Key == input);
if (pair.Key != null)
{
// Yes, we found it - use pair.Value
}
Any reason you're not just using a Dictionary<string, string> though? That's the more natural representation of a key/value pair collection:
var dictionary = new Dictionary<string, string>
{
{ "1", "abc" },
{ "2", "def" },
{ "3", "ghi" }
};
Then:
var value = dictionary[input];
Again, assuming you know the key will be present. Otherwise:
string value;
if (dictionary.TryGetValue(input, out value))
{
// Key was present, the value is now stored in the value variable
}
else
{
// Key was not present
}
Why are you not using a Dictionary? http://msdn.microsoft.com/en-us/library/xfhwa508.aspx
It seems to me this would solve your problem, and it's much easier to use.
Related
I'm trying to find the most time efficient way of classifying expenses on a piece of Accounting Software. The values come in like this:
"EFTPOS Kathmandu 2342342"
I have created a method as follows:
private static string Classifier(string inputDescription)
{
Dictionary<string, string> classified = new Dictionary<string, string>();
classified.Add("D/C FROM", "INCOME" );
classified.Add("CREDIT ATM", "INCOME");
classified.Add("INTEREST", "INCOME");
classified.Add("EFTPOS", "EXPENSE" );
classified.Add("DEBIT DEBIT", "EXPENSE");
classified.Add("CC DEBIT", "EXPENSE");
classified.Add("PAYMENT RECEIVED", "TRANSFER");
classified.Add("PAYMENT - THANK YOU", "TRANSFER");
classified.Add("IRD", "TAX" );
classified.Add("I.R.D", "TAX");
try
{
// What do I do here to get the value?
return value;
}
catch(Exception)
{
return "OTHER";
}
}
Basically, I want to run through the values of my inputDescription against the keys in the dictionary to get its value (the classification of the line item).
So for the example shown above, the result would be "EXPENSE".
I assumed dictionary would be the fastest way to approach this, but open to suggestions on better methods.
Thanks in Advance!
What about using RegEx?
const string EXPENSE_PATTERN = "^(EFTPOS|DEBIT DEBIT|CC DEBIT)"
const string ..._PATTERN
if (Regex.IsMatch(input, EXPENSE_PATTERN)){
return "EXPENSE";
} else if (Regex.IsMatch(input, INCOME_PATTERN)){
return "INCOME";
} else if (Regex.IsMatch(input, ..._PATTERN)){
return "...";
} else {
return "OTHER"
}
One of the way to achieve this is
string input = "EFTPOS Kathmandu 2342342";
string value = string.Empty;
foreach (var key in input.Split(' '))
{
value = classified.Where(k => classified.ContainsKey(k.Key)).Select(k => classified[k.Key]).FirstOrDefault();
if(value != null & value.trim()!= string.empty)
break;
}
Check the value is null or not for further use. foreach loop will break once will find value.
Calling method:
static void Main(string[] args)
{
Console.WriteLine(Classifier("EFTPOS Kathmandu 2342342"));
Console.WriteLine(Classifier("D/C FROM Kathmandu 2342342"));
Console.ReadKey();
}
Classifier method:
private static string Classifier(string inputDescription)
{
var classified = new Dictionary<string, string>
{
{ "D/C FROM", "INCOME" },
{ "CREDIT ATM", "INCOME" },
{ "INTEREST", "INCOME" },
{ "EFTPOS", "EXPENSE" },
{ "DEBIT DEBIT", "EXPENSE" },
{ "CC DEBIT", "EXPENSE" },
{ "PAYMENT RECEIVED", "TRANSFER" },
{ "PAYMENT - THANK YOU", "TRANSFER" },
{ "IRD", "TAX" },
{ "I.R.D", "TAX" }
};
try
{
foreach (var kvp in classified)
if (inputDescription.StartsWith(kvp.Key))
return kvp.Value;
return "OTHER";
}
catch
{
return "OTHER";
}
}
Returns:
EXPENSE
INCOME
Of course you could move the Dictionary definition outside of the method and make it a class member. That would especially make sense if you have multiple frequent calls to Classifier. You could also define it as an IReadOnlyDictionary to prevent changes to its contents.
The easiest way to get something from a dictionary is by using the key like:
Dictionary<string, string> classified = new Dictionary<string, string>();
var value = classified[key];
but of-course you would wanna check for the key occurence in dictionary like:
if(classified.ContainsKey(key))
return classified[key];
else
throw new InvalidTypeException();//this is because you should have all the key's mapped i.e you are only expecting known key types.People prefer other types like they would return null but i throw coz my dictionary is not having this key
Now coming to the values:
All the Values seem to be known and repeated types.So i would build an enum:
enum TransactionType
{
Expense,
Income,
Transfer
}
enum Source
{
EFTPOS,
DEBIT DEBIT,
...so on...
}
i prefer enums to avoid magic strings and people do make mistakes while typing strings.
So with the Combination of Dictionary and enum now i would build as :
private Dictionary<Source,TransactionType> PopulateSource()
{
Dictionary<Source,TransactionType> classified = new Dictionary<Source,TransactionType>();
//populate dictionary by iterating using
var keys = Enum.GetValues(typeof(Source));
var values = Enum.GetValues(typeof(TransactionType));
you can just iterate through keys if your keys and values in enum are in order .
return classified ;
}
public void TestSourceTransaction()
{
TransactionType transType;
var classifieds = PopulateSource();
var key = GetSourceType(inputDescription);//you need to write a method to get key from desc based on regex or string split options.
if(classifieds.ContainsKey(key))
classifieds[key].Value;
else
throw new InvalidTypeException("Source type undefined");
}
I prefer clean and expandable code and absolute no to magic string.
I have a Dictionary<string, decimal?>, and i would like to be able to sum the decimals by distinct string. So say i have the below inputs in dictionary,
"1", 20.00
"1", 35.00
"2", 10.00
"3", 15.00
"3", 30.00
I would like the following output to a new Dictionary
"1", 55.00
"2", 10.00
"3", 45.00
I'm guessing it would be something like
foreach(var item in dictionary)
{
newDictionary.Add(not sure what would go here, maybe some sort of linq query for distinct and sum?);
}
Assuming the same List of key value pairs as in the other answers:
var myList = New List<KeyValuePair<string, decimal?>> {
new KeyValuePair<string, decimal?>("1", (decimal)10.00),
new KeyValuePair<string, decimal?>("1", (decimal)15.00),
new KeyValuePair<string, decimal?>("2", (decimal)20.00),
new KeyValuePair<string, decimal?>("3", (decimal)30.50),
new KeyValuePair<string, decimal?>("3", (decimal)17.500)
};
var myResults = myList.GroupBy(p => p.Key)
.ToDictionary(g => g.Key, g=>g.Sum(p=>p.Value))
The keys in a dictionary can't be repeated, so the 2 first entries won't fit in a dictionary.
I think you may have a list of objects that you can loop, then you can use a dictionary to store the total for each "key"
something like
Dictionary<string, double> totals = new Dictionary<string, double>();
List<Tuple<string, double>> entries = new List<Tuple<string, double>>() {
new Tuple<string, double>("1",20.00),
new Tuple<string, double>("1",35.00),
new Tuple<string, double>("2",10.00),
new Tuple<string, double>("3",15.00),
new Tuple<string, double>("3",30.00)
};
foreach (var e in entries)
{
if (!totals.Keys.Contains(e.Item1))
{
totals[e.Item1] = 0;
}
totals[e.Item1] += e.Item2;
}
You can not have Dictionary object with duplicate keys. You would see ArgumentException when you try to add an existing key into the Dictionary object.
Refer: https://msdn.microsoft.com/en-us/library/xfhwa508(v=vs.110).aspx
As mentioned here You can't use Dictionary if you are using same keys, because they must be Unique.
You can use list of KeyPair though, which is closest to Dictionary, then you're code will look like this:
List<KeyValuePair<string, decimal?>> myList = new List<KeyValuePair<string, decimal?>>();
myList.Add(new KeyValuePair<string, decimal?>("1", (decimal)10.00));
myList.Add(new KeyValuePair<string, decimal?>("1", (decimal)15.00));
myList.Add(new KeyValuePair<string, decimal?>("3", (decimal)30.50));
myList.Add(new KeyValuePair<string, decimal?>("3", (decimal)17.500));
Dictionary<string, decimal?> sums = new Dictionary<string, decimal?>(); //This can be a dictionary because the keys will be unique after grouping
foreach (var item in myList.GroupBy(m => m.Key))
{
string currentKey = item.FirstOrDefault().Key;
sums.Add(currentKey, myList.Where(j => j.Key == currentKey).Sum(o => o.Value));
}
I am still a beginner with C# so I am sure I am missing some fundamental concept here but I am struggling with this.
I am trying to make a new collection from two existing collections.
The first is a Dictionary<string, someModel[]>
The second is a Dictionary<string, string>
I am trying to find matches between the two dicts keys and if they match make a new myOtherModelwith the values from the two dicts, but if they don't match I still want to make new myOtherModel but with an empty string for the missing value then add all those new myOtherModel will be added to a list.
The new myModel object will be one of two scenarios
For example: Dict1.Keys = 1,2,3,4....100. Dict2.Keys = 5,9,27,55
myList.Add(new myModel = {1, "", someModel[]}) //did not find a match
myList.Add(new myModel = {5, dict2.MatchingValue, someModel[]}) // did find a match
So basically, compare two dictionaries, for each item in the larger dictionary, make a new myModel with the item's values (one of them will be empty). But if that item's key matches a key in the other dictionary, grab the second dictionary's value and slap that in the new myModel
I tried messing around with a Tuples but I wasn't able to manipulate them how I wanted to.
This is what I have so far, but instead of giving me 490 items (the count from dict1) I get the 44k (the amount of the two being multiplied together)
foreach (var pair in dict1)
{
foreach (var item in dict2)
{
if (item.Key == pair.Key)
{
var x = new myModel()
{
prop1 = item.Value,
prop2 = pair.Key,
prop3 = pair.Value
};
myListOfModels.add(x);
}
else
{
var x = new myModel()
{
prop1 = "",
prop2 = pair.Key,
prop3 = pair.Value
};
myListOfModels.add(x);
}
}
}
You're looping through the second collection each time you iterate through the first collection which is why you're seeing too many results. You can easily simplify your code with a simple bit of Linq...
foreach (var pair in dict1)
{
// Get the matched value. If there isn't one it should return the default value for a string.
var matchedValue = dict2.Where(x => x.Key == pair.Key).Select(x => x.Value).SingleOrDefault();
var x = new myModel()
{
prop1 = matchedValue,
prop2 = pair.Key,
prop3 = pair.Value
};
myListOfModels.add(x);
}
I am trying to search through a dictionary to see if it has a certain value and if so then to change it.
Here is my code:
foreach (var d in dictionary)
{
if (d.Value == "red")
{
d.Value = "blue";
}
}
In visual studio when i step through the code debugging it i can see it change the value then when it hits the foreach loop to reiterate again it throws an exception
"Collection was modified; enumeration operation may not execute"
How do i fix this?
You can't change it in the middle of the foreach - you'll need to come up with some other mechanism, such as:
// Get the KeyValuePair items to change in a separate collection (list)
var pairsToChange = dictionary.Where(d => d.Value == "red").ToList();
foreach(var kvp in pairsToChange)
dictionary[kvp.Key] = "blue";
You can't modify a collection whilst you're enumerating over it (in a loop).
You'll need to add your changes to a collection, then change them separately. Something like:
var itemsToChange = dictionary
.Where(d => d.Value == "red")
.ToDictionary(d => d.Key, d => d.Value);
foreach (var item in itemsToChange)
{
dictionary[item.Key] = "blue";
}
If you want to replace all occurences of "red", you'll need to store the KeyValuePairs in a list or something like that:
var redEntries = dictionary.Where(e => e.Value == "red").ToList();
foreach (var entry in redEntries) {
dictionary[entry.Key] = "blue";
}
var dict = new Dictionary<string, string>()
{
{ "first", "green" },
{ "second", "red" },
{ "third", "blue" }
};
foreach (var key in dict.Keys.ToArray())
{
if (dict[key] == "red")
{
dict[key] = "blue";
}
}
You cannot modify the collection you are iterating over in a foreach loop. If you could do that, it would open up several problems, such as "Do I run it on this newly-added value too?"
Instead, you should do something like this:
foreach( string key in dictionary.Keys )
{
if( dictionary[key] == "red" )
{
dictionary[key] = "blue";
}
}
Objects in foreach loops are read-only.
Please read through this and this for more understanding.
I think it is not complicated but after doing some research I can't find an answer to a simple problem.
I am iterating through keys in a dictionary and I would like to use the key which is a string as a double in some calculation.
If I do this :
foreach (KeyValuePair<string, List<string> price in dictionary)
double ylevel = Convert.ToDouble(price.Key);
It seems to not work and I get a "Input string was not in a correct format" error.
What is the right way to get a double from the key..
Thanks
Bernard
You're doing it correctly.
The error message indicates that one of your keys is not actually a double.
If you step through this example in a debugger, you'll see it fails on the second item:
var dictionary = new Dictionary<string, List<string>>();
dictionary.Add("5.72", new List<string> { "a", "bbb", "cccc" });
dictionary.Add("fifty two", new List<string> { "a", "bbb", "cccc" });
foreach (KeyValuePair<string, List<string>> price in dictionary)
{
double ylevel = Convert.ToDouble(price.Key);
}
Solution
To resolve this problem, you should use the following code:
var dictionary = new Dictionary<string, List<string>>();
dictionary.Add("5.72", new List<string> { "a", "bbb", "cccc" });
dictionary.Add("fifty two", new List<string> { "a", "bbb", "cccc" });
foreach (KeyValuePair<string, List<string>> price in dictionary)
{
double ylevel;
if(double.TryParse(price.Key, out ylevel))
{
//do something with ylevel
}
else
{
//Log price.Key and handle this condition
}
}
This is telling you that the string (that happens to be the key, although this is unrelated to the problem) cannot be parsed into a double. Check the value of the string you are attempting to convert.
double ylevel = Convert.ToDouble(price.Key.GetHashCode());