Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I am having a return type of a function being set to IEnumerable<Dictionary<string, object>> and I need to get the key, value pairs.
Using the appropriate key, I need to change the value.
I have a solution when the return type is a Dictionary but not when IEnumerable<Dictionary<string, object>>
I finally need to modify the value after, the specific key is found.
These following solutions maybe what your looking for, However you'll have to work out which one is more appropriate based on your circumstances
Given
var myKey = "someKey";
Assuming, your list of dictionaries contains the key your looking for, only once
var aDictionary = MyEnumerable.Single(x => x.ContainsKey(myKey));
aDictionary[myKey] = myNewValue;
An InvalidOperationException will be thrown if
More than one key is found
No keys are found
Assuming your list of dictionaries may or may not contain the key your looking for, only once
var aDictionary = MyEnumerable.SingleOrDefault(x => x.ContainsKey(myKey));
if(aDictionary != null)
{
aDictionary[myKey] = myNewValue;
}
An InvalidOperationException will be thrown if
More than one key is found
Assuming there may be multiple occurrences of your key
foreach (var aDictionary in MyEnumerable.Where(x => x.ContainsKey(myKey)))
{
aDictionary[myKey] = myNewValue;
}
Update
It seems you might be confused with the type IEnumerable<Dictionary<string, object>>
IEnumerable is a list (for the point of this conversation)
A Dictionary represents a collection of keys and values.
So what you have is a list of collections of keys and values
You can iterate through the IEnumerable> using a foreach sentence:
(this is just an example to help to illustrate)
IEnumerable<Dictionary<string, object>> colectionDict;
foreach(var dict in colectionDict) //dict is an object of type Dictionary<string,object>
Also, you can use a variable type Enumerator.
var enum = colectionDict.GetEnumerator();
while(enum.Next){
var dict = enum.Current; // dict is an object of type Dictionary<string,object>
}
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed last month.
Improve this question
In PHP and Python I can deserialise a JSON document to a dictionary structure. That's the default behaviour and there are not many other options anyway. In C#, hovever, all is typed and System.Text.Json methods want to know what type to deserialise into. Since I don't know the structure of the JSON document and just need to pass it on to something that can handle a dictionary, I need to convert it to that.
This doesn't work as expected:
var dict = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>("{ \"a\": 1, \"b\": { \"c\": 3 } }");
At least what the VSCode debugger shows me, I have a dictionary with the keys "a" and "b" but the values are anything. I'd expect to see an int as value for "a" and another Dictionary as value for "b" with an int for the value "c".
How can this be achieved?
I'm looking for something like this:
// Does not exist:
var dict = System.Text.Json.JsonSerializer.DeserializeToDictionary("{ \"a\": 1, \"b\": { \"c\": 3 } }");
I'm trying to convert a class that I've written in Python because I hit other roadblocks in Python. I'm more experienced in C# so I'd like to solve the problem there, but JSON for dynamic data isn't a strength of C#. Seems I have to write some classes of my application in Python and others in C# to get it done.
Newtonsoft.Json fits much better for the complicated cases. You can try this code
using Newtonsoft.Json;
var jsonParsed = JObject.Parse(json);
var dict = new Dictionary<string, object>();
AddDictionaries(dict,jsonParsed);
public void AddDictionaries(Dictionary<string, object> dict, JObject jsonObj)
{
foreach (var prop in jsonObj)
{
if (prop.Value.Type != JTokenType.Object)
dict.Add(prop.Key, prop.Value);
else
{
var nestedDict = new Dictionary<string, object>();
AddDictionaries(nestedDict, (JObject)prop.Value);
dict.Add(prop.Key, nestedDict);
}
}
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
Still learning C# - is it possible to loop through elements of a string array and compare it with the values in a list of objects? eg:
var allFolks = new List<Folks>();
allFolks = Folks.GetAll();
string[] enteredNames = Array.ConvertAll(inputNames.Text.Split(','), p => p.Trim());
foreach (var eName in enteredNames)
{
//if eName is not in the list of allFolks throw an exception
if (!allFolks.Name.Contains(eName))
throw new Exception ("Name not found");
}
What would be the best way to compare each entered name (stored in an array) with the names in the list of type Folks? Is it possible to use Lambda Expression in the example above?
string[] enteredNames = inputNames.Split(',');
foreach (var eName in enteredNames)
{
if (!allFolks.Any(e => e.Name.Contains(eName.Trim()))
{
throw new Exception("Name not found");
}
}
Taking a string of inputNames and calling .Split(',') will separate the string by each comma and save them into a string[].
Then if (!allFolks.Any(e => e.Name.Contains(eName))) will throw the exception if eName does not exist within any object in the List<Folks>.
It's a difficult to asnwer for "what is the best" question: the best in performance, memory, readability?
I suggest using Linq in order to query the collections:
using System.Linq;
...
// Do we have any unknown name (i.e. any namy name except folks' names)?
bool hasUnknownName = inputNames
.Text
.Split(',', StringSplitOptions.TrimEntries)
.Except(allFolks.Select(folk => folk.Name))
.Any();
if (hasUnknownName)
throw ... //TODO: don't throw Exception, but some derived class
Linq solution
Often is more readable
Faster then initial one (if allFolks and inputNames are large)
Edit: As Eric J. puts in the comment below, it's possible to improve performance when allFolks is large and has duplicates. We can, for instance, efficiently compare with (precomputed) unique names only:
// We precompute unique names to test
HashSet<string> uniqueNames = new HashSet<string>(allFolks
.Select(folk => folk.Name));
...
bool hasUnknownName = inputNames
.Text
.Split(',', StringSplitOptions.TrimEntries)
.Any(name => !uniqueNames.Contains(name));
if (hasUnknownName)
throw ... //TODO: don't throw Exception, but some derived class
If I am to infer your requirements, I think you wish to validate a list of names, held as strings, and check to ensure each one matches the Name of one of your Folk objects.
You can do it with LINQ this way:
bool invalid = enteredNames.Any( x => !allFolks.Any( y => y.Name == x) );
For a large list of Folk objects, you'll get better performance if you extract the unique set of names to a variable of its own.
var knownGoodNames = allFolks.Select( x => x.Name ).ToHashSet();
bool invalid = enteredNames.Any( x => !knownGoodNames.Contains(x) );
I have a dictionary fooDictionary<string, MyObject>.
I am filtering the fooDictionary to get only the MyObject with a specific value of the property.
//(Extension method is a extension method that I made for the lists
//(PS: ExtensionMethod returns only 1x MyObject))
fooDictionary.Values.Where(x=>x.Boo==false).ToList().ExtensionMethod();
But I also want to get the keys of the already filtered MyObject's. How can I do that?
Instead of just pulling the values, query the KeyValuePair
fooDictionary.Where(x => !x.Value.Boo).ToList();
This will give you all the key value pairs where the MyObject has a Boo value of false.
Note: I changed your line x.Value.Boo == false to !x.Value.Boo as that is the more common syntax and is (IMHO) easier to read/understand the intent.
EDIT
Based on you updating the question to change from dealing with a list to this new ExtensionMethod here is an updated answer (I am leaving the rest as is as it answers what the original posted question was).
// Note this is assuming you can use the new ValueTuples, if not
// then you can change the return to Tuple<string, MyObject>
public static (string key, MyObject myObject) ExtensionMethod(this IEnumerable<KeyValuePair<string, MyObject>> items)
{
// Do whatever it was you were doing here in the original code
// except now you are operating on KeyValuePair objects which give
// you both the object and the key
foreach(var pair in items)
{
if ( YourCondition ) return (pair.Key, pair.Value);
}
}
And use it like this
(string key, MyObject myObject) = fooDictionary.Where(x => !x.Value.Boo).ExtensionMethod();
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question appears to be off-topic because it lacks sufficient information to diagnose the problem. Describe your problem in more detail or include a minimal example in the question itself.
Closed 8 years ago.
Improve this question
I understand, that it sounds a little bit strange, but I use triple nested dictionary in my program. It is the most suitable form for my data representation.
Code sample:
Dictionary<string, IDictionary> outerDictionary;
Dictionary<string, IDictionary> middleDictionary;
Dictionary<string, string> innerDictionary;
As you can suspect from names : innerDictionary is "Value" of middleDictionary and middleDictionary is "Value" of outerDictionary;
And I am trying to iterate through it, I need to get values from the inner Dictionary. I think I got stucked with this simple task.
Would really appreciate any help.
Thanks in advance.
PS > Thanks a lot for all your help!
If you just want a flat list of all values, you can do that with a chained SelectMany:
outerDictionary.SelectMany(d => d.Value) // middle Dictinoary
.SelectMany(d => d.Value)
.Select(kvp => kvp.Value); // inner Dictionary
Brute force:
foreach(KeyValuePair<string, IDictionary> entryOuter in outerDictionary)
{
foreach(KeyValuePair<string, IDictionary> entryMiddle in entryOuter.Value)
{
foreach(KeyValuePair<string, string> entry in entryMiddle.Value)
{
// do something with entry.Value
}
}
}
If your outerDictionary is declared like this
Dictionary<string,Dictionary<string,Dictionary<string,string>>> outerDictionary;
you can iterate the innermost values like this:
var innermost = outerDictionary.Values
.SelectMany(v1 => v1.Values.SelectMany(v2 => v2.Values));
If for some reason you are using non-generic dictionaries, but you are on .NET 3.5 or later, you fix this by adding a call to Cast<>, like this:
var innermost = outerDictionary.Values.Cast<Dictionary<string,Dictionary<string,string>>>
.SelectMany(v1 => v1.Values.SelectMany(v2 => v2.Values));
As described in the documentation, the Values property is an enumeration of all values contained; so you could use
foreach ( var middleDictionary in outerDictionary.Values )
{
foreach ( var innerDictionary in outerDictionary.Values )
{
foreach ( string iString in innerDictionary.Values )
{
// your code
}
}
}
You should probably be using a different data structure that's easier to think about than tripledecker Dictionaries. Even if you don't, you should definitely use typed Dictionaries:
Dictionary<string, Dictionary<string, Dictionary<string, string>>> TripleDictionary;
You can then itereate throgh them like so:
foreach (KeyValuePair<string, IDictionary> first in TripleDictionary)
{
foreach (KeyValuePair<string, IDictionary> second in first.Value)
{
foreach (KeyValuePair<string, string> third in second.Value)
{
string x = third.Value;
// Do stuff
}
}
}
Implicit types will make it more readable:
foreach (var first in TripleDictionary)
{
foreach (var second in first.Value)
{
foreach (var third in second.Value)
{
string x = third.Value;
// Do stuff
}
}
}
I have number of lists of type:
public List<KeyValuePair<KeyValuePair<string, string>,
List<KeyValuePair<string, string>>>> rawComparisonObject;
I want to get the intersection of these lists according to the "key" of the KeyValuePair that constructs the List
I tried:
List2 = list1.Intersect(list2).Intersect(list3)...... etc , but as you can see it Intersects all the KeyValuePair variable, not the one I want.
I also tried
Intersect lists on KeyValuePair key?
In the following form:
public List<List<KeyValuePair<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>>> getCommon(List<ResourceInformation> input)
{
List<List<KeyValuePair<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>>> rawComparisonObject =
new List<List<KeyValuePair<KeyValuePair<string,string>,List<KeyValuePair<string,string>>>>>();
foreach (ResourceInformation item in input)
{
rawComparisonObject.Add(item.rawComparisonObject);
}
foreach (List<KeyValuePair<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>> item in rawComparisonObject)
{
}
List<List<KeyValuePair<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>>> common =
new List<List<KeyValuePair<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>>>();
for (int i = 0; i < (rawComparisonObject.Count-1); i++)
{
var keysFromB = new HashSet<KeyValuePair<string, string>>(rawComparisonObject[i].Select(x => x.Key));
var result = rawComparisonObject[i+1].Where(x => keysFromB.Remove(x.Key));
common.Add(result.ToList());
}
return common;
}
it returned very faulty values,
is there
Any easy way to do this ?
I use this data structure in linked data work, to get common objects as a result of comparing between objects
Ex: Batman vs. Inception
should return:
Type : Movie | Movie
Starring : Christian Bale | Leonardo Dicaprio
of course everything is highlighted with it's URI link, that's why I need keyValuePair one for URI and other for label....
I tried my best to explain this complex data-structure. hope it's clear enough
As I understand the code you've written, here's my (revised) translation:
public List<List<KeyValuePair<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>>> getCommon(List<ResourceInformation> input)
{
var rawComparisonObject =
input.Select(item => item.rawComparisonObject).ToList();
var common = rawComparisonObject.Zip(
rawComparisonObject.Skip(1),
(prevItems, nextItems) =>
(from next in nextItems
join prev in prevItems on next.Key equals prev.Key
select next).ToList()).ToList();
return common;
}
Edit: the above translation, omits the empty foreach loop in the middle and uses the join as a filter, projecting only the 'next' elements that pass the join criteria. I tend to favor join for this kind of filtering as I know it utilizes hashing under the covers to efficiently perform the matching it does.
The problem with my prior version was that it collected the join results using a 'group join' variable which led to that extra enumerable that we didn't want. After the change, the inner ToList() is analogous to the result variable in the original code sample provided in the post. The outer ToList() is the final common variable's (re)packaging of the results. I believe this will provide results similar to that of the original code; however, I strongly encourage testing to verify that the results meet expectations.
IMHO, the right thing to do would be to refactor to simplify the generics use until we can reason about them better. In a brief interim attempt I changed GetCommon to a generic type like this (later changing it back):
public List<List<KeyValuePair<T, List<T>>>> GetCommon<T>(/*List<ResourceInformation> input*/)
From there, we could promote the rawComparisonObject list to a parameter of the method - and in the process of doing so, we would replace the current parameter of the method. The use of var typing allows us to avoid changing the type for the common local variable (so long as we're careful that the output type matches the expected return type, which was my bad on the original translation.)
There are many more design ideas and questions than I could comfortably examine here, so I am going to close without attempting to do so. I do want to offer that this was a good challenge - sometimes LINQ isn't the right choice, but even when it isn't the right choice, a change of approach can make it worth trying. Thanks!
you can do this with linq, although likely you should change your data model to be more efficient:
var keys = list1.select( kv => kv.Key).intersection(list2.select(kv => kv.Key)
var result = list1.where( key => keys.contains(key).TolLst()
If you only want to intersect the KeyValuePairs on their key you should implement a custom IEqualityComparer<T> and use Intersect() method like this:
class KeyValyePairComparer : IEqualityComparer<KeyValuePair<string, string>>
{
public bool Equals(KeyValuePair<string, string> x, KeyValuePair<string, string> y)
{
return x.Key == y.Key;
}
public int GetHashCode(KeyValuePair<string, string> item)
{
return item.Key.GetHashCode();
}
}
Using the implementation above you can get the intersection with the query:
var comparer = new KeyValuePairComparer();
var intersection = list1.Intersect(list2, comparer).Intersect(list3, comparer);