Converting complex object to dictionary<string,string> - c#

I need to convert a dto object class like this :
public class ComplexDto
{
public ComplexDto()
{
ListIds = new List<ListIdsDto>();
}
public string Propertie1 { get; set; }
public string Propertie2 { get; set; }
public IList<int> ListIds { get; set; }
}
to a dictionary<string,string>.
This is just some class example, this class will be used as json object like this:
{"Propertie1":"ss","Propertie2":"","ListIds":[1,2,3]}
I need to pass this object to a FormUrlEncodedContent(dictionary) as dictionary of strings.
I have this :
var data = new Dictionary<string, string>();
data[string.Empty] = ComplexDto.ToJson();
And I would like to transform the ComplexDto.ToJson() or the ComplexDto object to a Dictionary string, string.
Any Ideas ?

Assuming that you have a collection with some ComplexDto instances like:
List<ComplexDto> complexDtoList = ...;
and you expect that there are duplicate keys which would cause an exception(otherwise you could have used a dictionary in the first place).
You can use Enumerable.GroupBy to get unique keys. Then you have to decide what you want to do with the 1-n Propertie2-strings per group. One way is to use String.Join to concat all with a separator:
Dictionary<string, string> result = complexDtoList
.GroupBy(dto => dto.Propertie1)
.ToDictionary(
p1Group => p1Group.Key,
p1Group => string.Join(",", p1Group.Select(dto => dto.Propertie2)));
You could also build a Dictionary<string, List<string>> and use p1Group.Select(dto => dto.Propertie2).ToList() as value.

Related

Removing specific values from a Dictionary C# with Linq

I have a dictionary which holds information from a parsed test run. The key is the name of the method and the value is a list of TestRunProperties. My dictionary contains all methods from a test run and I would like to remove the methods which failed during a test run. Is this possible to do with Linq?
TestRunProperties class:
public class TestRunProperties
{
public string computerName { get; set; }
public TimeSpan duration { get; set; }
public string startTime { get; set; }
public string endTime { get; set; }
public string testName { get; set; }
public string outcome { get; set; }
}
Dictionary:
//Key is the name of the method, value is the properties associated with each run
private static Dictionary<string, List<TestRunProperties>> runResults = new Dictionary<string, List<TestRunProperties>>();
I've tried this but I think I'm getting confused with the Where part:
runResults.Remove(runResults.Where(methodName => methodName.Value.Where(method => method.outcome.ToLower().Equals("failed"))));
I'm quite new to Linq and Lambda and I'm still trying to understand how to access data like this.
Just use a loop to remove the items you don't want. You can write an extension method to make it easier to call:
public static class DictionaryExt
{
public static void RemoveAll<K, V>(this IDictionary<K, V> dict, Func<K, V, bool> predicate)
{
foreach (var key in dict.Keys.ToArray().Where(key => predicate(key, dict[key])))
dict.Remove(key);
}
}
This usually will be more efficient than creating an entirely new dictionary, especially if the number of items being removed is relatively low compared to the size of the dictionary.
Your calling code would look like this:
runResults.RemoveAll((key, methodName) => methodName.Value.Where(method => method.outcome.ToLower().Equals("failed")));
(I chose the name RemoveAll() to match List.RemoveAll().)
You could create a new dictionary by filtering out the invalid ones:
var filtered = runResults.ToDictionary(p => p.Key, p => p.Value.Where(m => m.outcome.ToLower() != "failed").ToList());
Ok, grrrrrr was faster :-)
To be honest you're probably better off selecting a new dictionary from the existing one:
runResults.Select().ToDictionary(x => x.Key, x => x.Value.Where(x => x.Value.outcome != "failed"));
*editted to reflect list in the dictionary.
Actually, you can get rid of the ones with no successful results by doing this too:
runResults.Select(x => new { x.Key, x.Value.Where(x => x.Value.outcome != "failed")} ).Where(x => x.Value.Any()).ToDictionary(x => x.Key, x => x.Value);

Converting a distinct list to dictionary not working

I'm trying to convert a list of objects to a dictionary using the following code:
var MyDictionary = MyList.Distinct().ToDictionary(i => i.ObjectId, i => i);
I know that a dictionary should not contain duplicate elements, hence the .Distinct(). Yet I still get the following Exception whenever there's a duplicate element:
An item with the same key has already been added.
MyList is a list of MyObject that looks like this:
public class MyObject{
public string ObjectId { get; set; }
public string FName { get; set; }
public string LName { get; set; }
}
Is there a better way to create a dictionary from a list of objects ? or am I doing something wrong?
If you want to compare on the ObjectId, you'll need to pass in a custom comparer to .Distinct(). You can do so like this:
class MyObjectComparer : IEqualityComparer<MyObject>
{
public bool Equals(MyObject x, MyObject y)
{
return x.ObjectId == y.ObjectId;
}
public int GetHashCode(MyObject obj)
{
return obj.ObjectId.GetHashCode();
}
}
var MyDictionary = MyList
.Distinct(new MyObjectComparer())
.ToDictionary(i => i.ObjectId, i => i);
You could use Group by and then select first from the List as below:
var MyDictionary = MyList.GroupBy(i => i.ObjectId, i => i).ToDictionary(i => i.Key, i => i.First());
Distinct works using the objects built in Equals and GetHashCode methods by default but your dictionary works only over the id. You need to pass in a IEqualityComparer in to distinct that does the comparison on Id to test if items are equal or make MyObject implment Equals and GetHashCode and have that compare on the Id.

How to store multiple items in IDictionary?

I have this IDictionary declaration: IDictionary<string, string> trace;
Inside of it I want save a list of element returned by a json deserialization, actually I do this like:
var obj = JsonConvert.DeserializeObject<List<RootObject>>(responseText);
foreach (var item in obj)
{
trace["date"] = item.trace.details.date;
trace["type"] = item.trace.details.type;
foreach (var trace in item.trace.context.context)
{
trace["context"] = JsonConvert.SerializeObject(trace);
}
}
Now this code working good but save only the last item of the iteration, this 'cause when I iterate over the item the date, type etc... are replaced, but I want store the item not replace it in each new iteration.
How can do this with IDictionary?
Note that: trace.x is the name of the class that deserialize the json.
Further question: Maybe the use of IDictionary is not a good idea for achieve this?
Looks like you'd be better off using a dedicated class, something like this:
public class TraceInfo
{
public string Date { get; set; }
public string Type { get; set; }
public List<string> ContextItems { get; set; }
}
Then for every value in obj, create a TraceInfo object using new TraceInfo() and set its properties.
You can then store them in a List<TraceInfo> or in a Dictionary<string, TraceInfo>, the choice is yours.

Deserialize json array of dictionaries in c#

I have an array of dictionaries that I've created in javascript. After serializing to json I get the following string :
"[{\"key\":\"60236\",\"value\":\"1\"},{\"key\":\"60235\",\"value\":\"gdsfgdfsg\"},{\"key\":\"60237\",\"value\":\"1\"}]"
I am having a hard time getting this deserialized into either a list or dictionary in c#.
I've tried:
Dictionary<int, string> values = JsonConvert.DeserializeObject<Dictionary<int, string>>(Model.Json);
but that doesn't work.
There are several ways that you can extract your key/value pairs to construct a dictionary:
var dict = "[{\"key\":\"60236\",\"value\":\"1\"},
{\"key\":\"60235\",\"value\":\"gdsfgdfsg\"},
{\"key\":\"60237\",\"value\":\"1\"}]";
Use List<KeyValuePair<int, string>>
var dictionary = JsonConvert.DeserializeObject<List<KeyValuePair<int, string>>>(dict)
.ToDictionary(x => x.Key, y => y.Value);
Use a custom object that represents your pairs and then create a dictionary from your collection.
var output = JsonConvert.DeserializeObject<List<Temp>>(dict);
var dictionary = output.ToDictionary(x => x.Key, y => y.Value);
public class Temp
{
public int Key { get; set; }
public string Value { get; set; }
}
Finally, if you're uncomfortable with using a custom "throwaway" object just for deserialization, you can take a tiny performance hit and use dynamic instead.
var dictionary = JsonConvert.DeserializeObject<List<dynamic>>(dict)
.ToDictionary (x => (int)x.key, y => (string)y.value);
what i suggest is for try to see what actually your json represent. You can create a class here on Json2CSharp and the use this class/List of this class (depend on whether your json is in the form of array or simple class object).
Just pass type to JsonConvert.DeserializeObject class type part. for example
var output = JsonConvert.DeserializeObject<List<Class>>(json);
In your case is it just an array of Temp class
public class Temp
{
public string key { get; set; }
public string value { get; set; }
}
Sp all you need is :-
var output = JsonConvert.DeserializeObject<List<Temp>>(json);
The you can convert this list to dictionary as suggested in other answer:-
var dictionary = output.ToDictionary(x => x.Key, y => y.Value);
This always help me out. Hope it help you too.

Convert Dictionary<string, object> to a collection of objects with key

Is there a way to convert Dictionary<string, obj> to collection of objects such that each single object in the collection includes the key as another property
Here is the class def for obj
class someclass
{
string property1;
string property2;
}
After conversion, I am expecting each object in the collection to be like
obj.property1
obj.property2
obj.Key
I have been struggling with this since along time and I seek some help. any ideas?
thanks in advance.
Something like
var myCollection = from de in myDictionary
select new
{
de.Value.property1,
de.Value.property2,
de.Key
}.ToList(); // or .ToArray()
should do the trick.
That will return a List of a new anonymous type with the properties you requested.
You could also(in addition to the anonymous type apporach) use a List<Tuple<string, string, string>>:
var list= dictionary
.Select(kv => Tuple.Create(kv.Value.property1, kv.Value.property2, kv.Key))
.ToList();
foreach(var item in list)
{
Console.WriteLine("property1:{0 property2:{1} key:{2}"
, item.Item1
, item.Item2
, item.Item3);
}
The advantage over an anonymous type is that you can return the Tuple easily from a method.
Edit: A third option(my favorite) is simply to create instances of a class that you've declared somewhere. That's the ideal way. I don't know why i thought that you want a class "on the fly".
class someOtherClass
{
public string property1{ get; set; };
public string property2{ get; set; };
public string Key{ get; set; };
}
List<someOtherClass> objects = dictionary
.Select(kv => new someOtherClass(){
property1 = kv.Value.property1,
property2 = kv.Value.property2,
Key = kv.Key
})
.ToList();
You may use anonymous type if you don't want to store the result like this:
In case you just wana use it as datasource for example.
var res = myDictionary.Select(pair => new { pair.Key, pair.Value.Property1, pair.Value.Property2 });
The other answers are good, so this is just a supplement.
You could use arrays of Length three:
var arrays = myDictionary
.Select(kv => new[] { kv.Value.property1, kv.Value.property2, kv.Key, });
Or you could write a new class
class SomeclassAndKey
{
public string property1;
public string property1;
public string Key;
}
and then say
var someclassAndKeys = myDictionary
.Select(kv => new SomeclassAndKey { property1 = kv.Value.property1, property2 = kv.Value.property2, Key = kv.Key, });
In each case you could append .ToList() if you wanted not to defer enumeration and get a full List<> out.

Categories