Iterating over lists and summing and putting result in dictionary - c#

Suppose i have two (could be more) lists of same object having same fields/properties.
Each list represent the same object
Proerpties:
HoursWorked
HoursRate
I want to take iterate and take sum of each field from all lists (could be 2, 3, or so on) and store it in an dictionary with key value pair. e.g HoursWorked:2 and HourseRate:6
Currently, i am able to do it for only one field only (hard coded). I want to make it generic so i can fill dictionary with Key/Value for all fields.
I have defined my dictionary as follow
public Dictionary<string, double> TotalCount { get; set; }
Linq Query:
Dictionary<string, double> totalCount = records
.GroupBy(x => records)
.ToDictionary(x => Convert.ToString("HoursWorked"), x => x.Where(y => y.HoursWorked != null).Sum(y => y.HoursWorked).Value);
Any help on this?
Sample Data:
Input
report =
{
[HoursWorked: 1.0, HoursRate:10],
[HoursWork:2.0, HoursRate:15]
}
Expected Output
Dictioary = {Key:HoursWorked Value: 3.0,Key:HoursRate Value:25}

Dictionary<string, double> dictionary = new[] { "HoursWorked", "HoursRate" }
.ToDictionary(k => k, v => collections
.SelectMany(x => x)
.Sum(y => (double)y.GetType().GetProperty(v).GetValue(y)));
Where 'collections' is your collection of lists.
Obviously totally type unsafe and will fall down very easily!
I would argue that a much better pattern for this, as opposed to using reflection, would be to write a method or interface that will return the correct double value given the string key.

class someObject
{
public int workingHours { get; set; }
public int hourRate { get; set; }
}
You can create a common list from all list.
List<SomeObject> lst = new List<SomeObject>();
lst.AddRange(Oldlst1);
lst.AddRange(Oldlst2);
Then you can group by based on hour rate.
var n = lst.GroupBy(x=>x.hourRate);
And then you can create a dictionary.
var m=n.ToDictionary(x=>x.Key, x=>x.Sum(y=>y.workingHours));
Here in m you will get hourRate and in value you will get sum of working hour.

Related

Iterate over list inside a dictionary but 1 item from every list at a time

I have a dictionary Dictionary<string, List<string>> MatrixColumns whose content looks like this:
Now, I want to iterate over MatrixColumns Dictionary in such a way that I first get "condition#1" of [0] of key "OPERATOR_ID" and then "delta#1" of [0] of key "DELTA_ID"
and then again "condition#1" of 1 of key "OPERATOR_ID" and then "delta#1" of 1 of key "DELTA_ID" and so on.
Thing to keep in mind is the count of elements inside MatrixColumns can vary and it's not always 2. pls. guide me, How Can I achieve this?
Create a class:
public class MatrixColumnDto
{
public string ColumnName { get; set; }
public List<string> ColumnValues { get; set; }
}
Use LINQ as:
var MatrixColumnsResult = Enumerable.Range(0, MatrixColumns.Max(list
=> list.ColumnValues.Count))
.Select(i => MatrixColumns.Select(list => list.ColumnValues.ElementAtOrDefault(i)).ToList())
.ToList();

Dynamically constructing a GET query with optional parameters in C#

I have a class that contains all the properties of a query I'm constructing could possibly have (most of which are optional)
For example:
public class QueryClass
{
public string Offset {get; set;}
public string Limit {get; set;}
public string Sort {get; set;}
}
Then in a BuildQuery() method I am constructing the query by doing this:
private string BuildQuery(QueryClass query)
{
var queryDictionary = new Dictionary<string, string>();
if (!string.IsNullOrEmpty(query.Offset)
{
queryDictionary.Add("offset", query.Offset);
}
if (!string.IsNullOrEmpty(query.Limit)
{
queryDictionary.Add("limit", query.Limit);
}
if (!string.IsNullOrEmpty(query.Sort)
{
queryDictionary.Add("sort", query.Sort);
}
var content = new FormUrlEncodedContent(queryDictionary);
return content.ReadAsStringAsync().Result;
}
This works, but the issue is my actual QueryClass is significantly larger than this, there's got to be a better way to do this than to have a ton of IF statements for every optional property but I haven't been able to come up with a more elegant solution. I also don't care for adding the keys in the dictionary in this way, I probably need a new approach for how I structure the QueryClass.
If you don't mind taking the reflection hit, just project, filter nulls, then send to ToDictionary
Note : The assumptions here are, all the property names are your keys, and all the properties are convertible to string
var queryClass = new QueryClass()
{
Limit = "asdf",
Sort = "Bob"
};
var results = queryClass
.GetType()
.GetProperties()
.Select(x => (Value: x.GetValue(queryClass) as string, x.Name))
.Where(x => !string.IsNullOrWhiteSpace(x.Value))
.ToDictionary(
x => x.Name.ToLower(),
x => x.Value);
foreach (var (key, value) in results)
Console.WriteLine($"{key} : {value}");
Output
limit : asdf
sort : Bob
Add pepper and salt to taste
Or as an extension method
public static IDictionary<string, string> ConvertToDictionary<T>(this T source)
=> typeof(T).GetProperties()
.Select(x => (Value: x.GetValue(source) as string, x.Name))
.Where(x => !string.IsNullOrWhiteSpace(x.Value))
.ToDictionary(
x => x.Name.ToLower(),
x => x.Value!);

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.

List to Dictionary<Key, List<Value>> - C#

I have a List and MyClass is:
public class MyClass
{
public bool Selected { get; set; }
public Guid NoticeID { get; set; }
public Guid TypeID { get; set; }
}
My question is, how do i convert this list into a Dictionary<Guid, List<Guid>>, where the dictionary key is the GUID from the TypeID property, and the value is a list of all the NoticeID values corresponding to that TypeID. I have tried like so:
list.GroupBy(p => p.TypeID).ToDictionary(p => p.Key, p => p.ToList())
but this returns a Dictionary <Guid, List<MyClass>>, and I want a Dictionary<Guid, List<Guid>>.
Well, when you group you can specify the value you want for each element of the group:
var dictionary = list.GroupBy(p => p.TypeID, p => p.NoticeID)
.ToDictionary(p => p.Key, p => p.ToList());
However, I would strongly consider using a lookup instead of a dictionary:
var lookup = list.ToLookup(p => p.TypeID, p => p.NoticeID);
Lookups are much cleaner in general:
They're immutable, whereas your approach ends up with lists which can be modified
They express in the type system exactly what you're trying to express (one key to multiple values)
They make looking keys up easier by returning an empty sequence of values for missing keys, rather than throwing an exception

Querying nested lists

I have two classes:
public GeneralClassName
{
public GeneralClassName ()
{
SpecificList = new List<OtherClass>();
}
public string StringValue;
public string OtherStringValue;
public List<OtherClass> SpecificList;
}
and
public OtherClass
{
public string Name;
public string Number;
}
After a JSON deserialization I obtain a nice List<GeneralClassName>, the result I want is a Dictionary<string, int> whose value is the sum of the variabiles "Number" inside List<OtherClass> inside List<GeneralClassName>, while the key is the variabile Name.
In other words I'd like to sum Number grouping by Name.
Now, the only thing that came across my mind is a nested foreach, something like that:
Dictionary<string, int> resultDictionary = new Dictionary<string, int>();
foreach(List<OtherClass> listOtherClass in bigListGeneralClass.Select(x => x.SpecificList))
{
foreach(OtherClass otherClass in listOtherClass)
{
int value = 0;
if(resultDictionary.ContainsKey(otherClass.Name))
{
resultDictionary[otherClass.Name] += otherClass.Number;
}
else
{
resultDictionary.Add(otherClass.Name, otherClass.Number);
}
}
}
While this solution seems to work well, I don't like it at all.
Is there a more clean way to find this result? Maybe through a nice LINQ query?
As you don't use any information from the GeneralClassName you can use SelectMany to flatten your list. This flat list of OtherClass instances is than grouped by the Name property. Finally, the list of groups is transformed into a dictionary with the key of the group (aka the Name property) being the key of the new property and the value being the sum of all Number values in that group:
var result = bigListGeneralClass.SelectMany(x => x.SpecificList)
.GroupBy(x => x.Name)
.ToDictionary(x => x.Key,
x => x.Sum(y => y.Number));
This code assumes that OtherClass.Number is in fact an int not a string. This assumption is also used in your sample code with the loop.
If this assumption is not correct, change y.Number to int.Parse(CultureInfo.InvariantCulture, y.Number).
Note: This will throw an exception if any of the numbers can't be parsed, so you might want to make sure beforehand that all contain valid numbers.
Try this:
Dictionary<string, int> result =
bigListGeneralClass.SpecificList.GroupBy(sl => sl.Name)
.ToDictionary(group => group.Key, group => group.Sum(x => Int32.Parse(x.Number)));

Categories