How can I go through different levels in a dictionary - c#

I've been reading a lot of documentation on how to iterate a Dictionary with a foreach, but I don't quite understand how I can go through the levels it has. For example:
I have "params" Dictionary, I add string and object values ​​to it, with .Add(), and to one of them I add a level called "item".
From what I understand, with the Foreach(KeyValueaPair<>) it is to iterate through the Dictionary. Do I need to use another foreach(KeyValuePair<>) to be able to loop through the second level?
For example, I want "param" to get the value of the element that Posnr brings
IDictionary<string, object> params = new Dictionary<string, object>();
params.Add("Customerid", zwCustomer.Customerid);
params.Add("PedidoCli", zwCustomer.PedidoCli);
params.Add("PedidoSap", zwCustomer.PedidoSap);
params.Add("TFacturaMat", new Dictionary<string, object>()
{
{
"item", new Dictionary<string, object>()
{
{"Vbeln", zfacturaMats.Vbeln},
{"Posnr", zfacturaMats.Posnr},
{"Matnr", zfacturaMats.Matnr},
}
},
});
foreach(KeyValuePair<string, object> item in parametros)
{
param = $"{item.Key} : {item.Value}";
}

No, you can do that directly. The Dictionary<TKey, TValue> class of the .NET library already does all that magic for you.
With the foreach loop
foreach(KeyValuePair<string, object> item in params)
{
Console.WriteLine($"{item.Key} : {item.Value}");
}
you already iterate trough all the elements of your dictionary. From an usage point of view this works exactly the same as if params was a List (except that there's no guaranteed order).
If you want a particular element, you have multiple possibilities, but in the easiest case you can just get an element by var myValue = params["PosNr"]. Alternatively you can use the TryGetValue() method to test whether a certain key is present.
So bottom line: It's interesting to know how a dictionary works internally, but when you use the .NET libraries, you don't have to care about that. Iterating and accessing works just out of the box.

Related

Create dictionary outside and initialize it using LINQ

I have dictionary indices and want to add several keys to it from another dictionary using LINQ.
var indices = new Dictionary<string, int>();
var source = new Dictionary<string, int> { { "1", 1 }, { "2", 2 } };
source.Select(name => indices[name.Key] = 0); // doesn't work
var res = indices.Count; // returns 0
Then I replace Select with Min and everything works as expected, LINQ creates new keys in my dictionary.
source.Min(name => indices[name.Key] = 0); // works!!!
var res = indices.Count; // returns 2
Question
All I want to do is to initialize dictionary without foreach. Why dictionary keys disappear when LINQ is executed? What iterator or aggregator I could use instead of Min to create keys for a dictionary declared outside of LINQ query?
Update #1
Decided to go with System.Interactive extension.
Update #2
I appreciate and upvote all answers, but need to clarify that, purpose of the question is not to copy a dictionary, but to execute some code in a LINQ query. To add more sense to it, I actually have hierarchical structure of classes with dictionaries and at some point they need to be synchronized, so I want to create flat, non-hierarchical dictionary, used for tracking, that includes all hierarchical keys.
class Account
{
Dictionary<string, User> Users;
}
class User
{
Dictionary<string, Activity> Activities;
}
class Activity
{
string Name;
DateTime Time;
}
Now I want to sync all actions by time, so I need a tracker that will help me to align all actions by time, and I don't want to create 3 loops for Account, User, and Activity. Because that would be considered a hierarchical hell of loops, the same as async or callback hell. With LINQ I don't have to create loop inside loop, inside loop, etc.
Accounts.ForEach(
account => account.Value.Users.ForEach(
user => user.Value.Activities.ForEach(
activity => indices[account.Key + user.Key + activity.Key] = 0));
Also, having loops where it can be replaced with LINQ can be considered as a code smell, not my opinion, but I totally agree, because having too many loops you will probably end up in duplicated code.
https://jasonneylon.wordpress.com/2010/02/23/refactoring-to-linq-part-1-death-to-the-foreach/
You can say that LINQ is used for querying, not for setting a variable, I would say I'm querying ... the KEYS.
Linq is not intended to be used to mutate the elements of a sequence. Rather, it is intended to be used to traverse, filter and project elements of a sequence. In this respect, it is intended to be used more in a "functional programming" style.
As you have discovered, Linq can be used in other than a functional programming style - but by using it in that way you are really misusing it.
Technically, the reason that source.Min() has the effect you were looking for is that it has to visit each of the elements of your sequence in order to determine the minimum element.
Because your selector for Min() has a side-effect (i.e. indices[name.Key] = 0) then a side-effect of finding the minimum value is to add each element's key to indices, but with a value of zero rather than the original value.
(I suspect you might have meant to put indices[name.Key] = name.Value...)
The reason that your use of Select() has no effect is that it has not been used to traverse the sequence - it uses "deferred execution".
You can force it to traverse the sequence by counting the elements, like so:
source.Select(name => indices[name.Key] = 0).Count();
However, that is also counter-intuitive and is a misuse of Linq.
The correct solution is to use foreach. This expresses your intent clearly and unambiguously.
An alternative approach is to write an AddRange() extension method for Dictionary like so:
public static class DictionaryExt
{
public static Dictionary<TKey, TValue> AddRange<TKey, TValue>(
this Dictionary<TKey, TValue> self,
IEnumerable<KeyValuePair<TKey, TValue>> items)
{
foreach (var item in items)
{
self[item.Key] = item.Value;
}
return self;
}
}
Then you can just call indices.AddRange(source); to achieve your aim.
Interestingly, the ImmutableDictionary type does already have an AddRange() method that you could use like so:
var indices = ImmutableDictionary.Create<string, int>();
var source = new Dictionary<string, int> { { "1", 1 }, { "2", 2 } };
indices = indices.AddRange(source);
Console.WriteLine(indices.Count);
But I wouldn't recommend you change over to using ImmutableDictionary just so you can use its AddRange().
Also note that ImmutableDictionary is, well, immutable - so you can't just do indices.AddRange(source);; you have to assign the result back as in indices = indices.AddRange(source); (like when you modify a string using ToUpper()).
You wrote:
All I want to do is to initialize dictionary without foreach
Do you want to replace the values in your indices dictionary with the values in source? Use Enumerable.ToDictionary
indices = (KeyValuePair<string, int>)source // regard the items in the dictionary as KeyValuePairs
.ToDictionary(pair => pair.Key, // the key is the key from original dictionary
pair => pair.Value); // the value is the value from the original
Or do you want to add the values from source to the already existing values in indices? If you don't want a foreach you'll have to take the current values from both dictionaries and Concat them to the values from source. Then use the ToDictionary to create a new Dictionary.
indices = (KeyValuePair<string, int>) indices
.Concat(KeyValuePair<string, int>) source)
.ToDictionary(... etc)
However this would be a waste of processing power.
Consider creating extension functions for Dictionary. See Extension Methods Demystified
public static Dictionary<TKey, TValue> Copy>Tkey, TValue>(
this Dictionary<TKey, TValue> source)
{
return source.ToDictionary(x => x.Key, x => x.Value);
}
public static void AddRange<TKey, TValue>(
this Dictionary<TKey, TValue> destination,
Dictionary<TKey, TValue> source)
{
foreach (var keyValuePair in source)
{
destination.Add(keyValuePair.Key, keyValuePair.Value);
// TODO: decide what to do if Key already in Destination
}
}
Usage:
// initialize:
var indices = source.Copy();
// add values:
indices.AddRange(otherDictionary);

C# getting values from Dictionary<string, List<object>>

I have a question about how to get values from my Dictionary<string, List<object>>, I tried all examples which I found in google, but still can't get something readable value.....
so, here is the code:
List<object> listValues = new List<object>();
listValues.Add(risk);
listValues.Add(validFrom);
listValues.Add(effectiveDate);
Dictionary<string, List<object>> dic = new Dictionary<string, List<object>>();
dic.Add(nameOfInsuredObject, listValues);
foreach (object value in dic.Values)
{
System.Console.WriteLine(value);
}
I can get key from dictionary, but with getting value I am stucked now....
And here is the result of this code:
Key => testInsObj
Values => System.Collections.Generic.List`1[System.Object]
So can anyone help me with it? I am new in C#, so maybe this is easy questions for others....
It seems you are looking for writing values of the list this way:
foreach (var value in dic.Values)
{
value.ForEach(Console.WriteLine);
}
In fact each element of the Dictionary is <string, List<Object>>. So, when you want to write Value part of the pair to console, you need a for loop to write each element of the List<object>.
It is confusing for new C# users, how to access the dictionary.
When you do a foreach on the dictionary, you get a KeyValuePair<TKey, TValue>. Now this KeyValuePair<TKey, TValue>, has 2 properties KeyValuePair.Key and KeyValuePair.Value, representing the Key and Value stored in the dictionary.
Also, the Value in your case is a List<T>, which means doing a Console.WriteLine on it will not print the whole List<T> (as some people expect), but just some reference string. You will have to "loop" over the list to print individual elements. Needless to say, depending on what you want to do with the element in the List<T>, you can use LINQ or some other common C# idiom.
foreach (var value in dic) {
Console.WriteLine(value.Key);
foreach (var item in value.Value)
Console.WriteLine(item);
}

Creating dictionaries with pre-defined keys C#

I'm looking for a way to define a dictionary for reuse. ie. I can create the dictionary object without having to populate it with the values I want.
Here is what I have currently (note code not tested, just example)
public Dictionary<string, string> NewEntryDictionary()
{
Dictionary<string, string> dic = new Dictionary<string, string>();
// populate key value pair
foreach(string name in Enum.GetNames(typeof(Suits))
{
dic.Add(name, "");
}
return dic;
}
The end result should be a new dictionary object with a predefined set of keys.
But I want to avoid doing it this way.
It's not really clear whether you're concerned about the amount of code you've written, or the efficiency of it. From an efficiency perspective, it's fine - it's O(N), but that's hard to avoid if you're populating a dictionary with N entries.
You can definitely make the source code shorter though, using LINQ:
public Dictionary<string, string> NewEntryDictionary()
{
return Enum.GetNames(typeof(Suits)).ToDictionary(name => name, name => "");
}
That won't be any more efficient, of course... it's just shorter code.
If you do ONLY want to save values according to your enum, use
Dictionary<Suits,String> instead of Dictionary<String,String>
Everything else, Jon already said. Use LinQ for a bit more "fancy" look. But that does not do better performance

What type is the best for loose numerically-indexed lists in C#?

What I need is something like an array but letting me to assign an element to whatever an index at any time and check if there is already a value assigned to particular index approximately like
MyArray<string> a = new MyArray<string>();
a[10] = "ten";
bool isTheFifthElementDefined = a[5] != null; // false
Perhaps Dictionary<int, string> with its ContainsKey method could do, but isn't there a more appropriate data structure if I want an ordered collection with numeric keys only?
I am also going to need to iterate through the defined elements (with foreach or linq preferably) accessing both the value and the key of current element.
As you mentioned Dictionary seems more appropriate for this.But you can do it with generic lists,for example, when you are creating your list you can specify an element count,and you can give a default temporary value for all your elements.
List<string> myList = new List<string>(Enumerable.Repeat("",5000));
myList[2300] = "bla bla bla..";
For int:
List<int> myList = new List<int>(Enumerable.Repeat(0,5000));
For custom type:
List<MyClass> myList = new List<MyClass>(Enumerable.Repeat(new MyClass(), 100));
Ofcourse It is not the best solution...
Note: Also you can use SortedList instead of Dictionary if you want an ordered collection by keys:
SortedList<TKey, TValue> : Represents a collection of key/value pairs that are sorted by key based on the associated IComparer implementation.
If you need key/value pairs you cannot use a list, you'll need a Dictionary.
The implementation is pretty snappy so don't be too afraid about performance (as long as you don't put too much values in it).
You can iterate over it with
foreach(KeyValuePair<int, string> kvp in dict)
{
}
If you need to order it you can use a list:
List<int> ordered = new List(dict.Keys);
ordered.Sort();
foreach(int key in ordered)
{
}

Is there a an easier way to initialize a List<KeyValuePair<T, U>>, like a Dictionary<T, U>?

Actually I need something like List<KeyValuePair<T, U>> but I want to be able to initialize it like dictionary (i.e. without writing new KeyValuePair every time). Like this:
Dictionary<string, string> dic = new Dictionary<string, string>
{
{ "key1", "value1"},
{ "key2", "value2"}
};
EDIT: It turns out .NET does have a combination list/dictionary type already: OrderedDictionary. Unfortunately this is a non-generic type, making it rather less attractive in my view. However, it retains the insertion order if you just call Add repeatedly.
It's a little strange as calling Add does not affect entries where a key already exists, whereas using the indexer to add a key/value pair will overwrite a previous association. Basically it doesn't seem like a terribly nice API, and I would personally still avoid it unless your use case exactly matches its behaviour.
No, .NET doesn't have any insertion-order-preserving dictionaries. You could always write your own list-based type with the relevant Add method. This might even be one of the few places I'd consider extending an existing type:
public class KeyValueList<TKey, TValue> : List<KeyValuePair<TKey, TValue>>
{
public void Add(TKey key, TValue value)
{
Add(new KeyValuePair<TKey, TValue>(key, value));
}
}
Then:
var list = new KeyValueList<string, string>
{
{ "key1", "value1"},
{ "key2", "value2"}
};
An alternative is to use composition, but my gut feeling is that this is a reasonable use of inheritance. I can't place why I'm happy in this case but not usually, mind you...
Because you do not have a dictionary you cannot use a dictionary initiailzer. You have a list so you could use a list initializer which will be the closest you could get:
var l = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("key1", "value1"),
new KeyValuePair<string, string>("key2", "value2"),
};
Here's the minimum requirement for you to use dictionary initializer: the class must implement IEnumerable and the class must have a public method Add which takes 2 arguments (where the first argument represents the key and the second argument the value). So you could write a custom class which satisfies those requirements and you will be able to use the syntax you have shown in your question.
The code you have typed works fine - further to Mads Togersen's post about the implementation of collection initialisers, the compiler maps the brace-delimited entries ({"key1", "value1"} above) to an Add method on the collection with the same signature - in this case Dictionary.Add(TKey, TValue).

Categories