How to get count of Dictionary Value Collection in C# - c#

I'm trying to get the count of a dictionary's value collection, where a field of the collection item, matches the key in the collection, as well as the type.
So my collection looks like this, note the object is initialized, this is just pseudo code:
var results = Dictionary<string, List<CourseEnrollmentsByStudentSQLResult>();
Now the CourseEnrollmentsByStudentSQLResult is a data transfer object, that maps to the rows returned from my query.
public class CourseEnrollmentsByStudentSQLResult
{
public int StudentID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string College { get; set; }
public int CollegeId { get; set; }
public string Prefix { get; set; }
public string CourseNumber { get; set; }
public string Course { get; set; }
public int CourseId { get; set; }
public string Program { get; set; }
public string Term { get; set; }
public string Status { get; set; }
public List<StudentCoursesSQLResult> Courses { get; set; }
}
You will notice that my CourseEnrollmentsByStudentSQLResult class also has a collection of StudentCoursesSQLResult objects. This is the list I'm trying to get a count of, based on two conditions.
First that the course, which is the string KEY in the dictionary, matches the course of the StudentCoursesSQLResult and then I need to filter on the StudentCoursesSQLResult.Type.
Here is the StudentCoursesSQLResult class:
public class StudentCoursesSQLResult
{
public int StudentID { get; set; }
public int Position { get; set; }
public string Prefix { get; set; }
public string CourseNumber { get; set; }
public string Course { get; set; }
public string Type { get; set; }
}
Now to get the count I'm looping over my dictionary and outputting headers for each key, this is where I'm trying to output the count for the dictionary's value collection.
foreach(var result in results) {
<span class="label label-default label-fat">
#result.Value.SelectMany(r => r.Courses).Count(c => c.Course == result.Key && c.Type == "required")
</span>
}
But for some reason it's returning zero, when I know it shouldn't be.
Can someone please point me in the right direction? Everything I've found so far online has said to use SelectMany, but I'm not having any luck.
Here is a screenshot of the debug output for a single course for the dictionary's value collection, where the Type is "required".

Looking at your screen shot, "Advanced French I: Structure and Expression" doesn't match the key of "Medieval Art and Architecture", which explains the incorrect count.
Instead, filter the CourseEnrollmentsByStudentSQLResult collection to those matching the dictionary key, then select all courses in those matched records, and finally count the courses that are "required".
#result.Value.Where(r => r.Course == result.Key)
.SelectMany(r => r.Courses)
.Count(c => c.Type == "required");

A variation on vivat if you want to do this in a program:
var cnt = selections.Where(r => r.Key == "Items").SelectMany(r => r.Value).Count();
"Items" is the Key value within the collection. In my case I created this collection:
Dictionary<string, string[]> selections = new Dictionary<string, string[]>();
Then added a simple set of values based on a key:
selections.Add("Items", txtItems.Text.Replace("\n", "").Split('\r'));
Later on I wanted to check if there had been any values set so I used the above method to count. It works great and in initial testing it helped me discover I needed to cleanup text entries before setting them up.

Related

Find in dictionary in Mongo

I have to find in dictionary in a mongo database.
class Person
{
public string Name { get; set; }
public Dictionary<int,string> AgePersons { get; set; }
}
I have tried two options:
_database.Find(v => v.Name == "test" && v.AgePersons.Any(el => el.Key == 12 && el.Value == "person_name")).ToList();
I got the error: The expression tree is not supported: {document}{dc}'
_database.Find(v => v.Name == "test" && v.AgePersons[12] == "person_name"]).ToList();
I got the error: 'v.AgePersons.get_Item(12) is not supported.'
How can I solve?
A simple option would be to store your objects as:
public class Document
{
public String Name { get; set; }
public List<Item> People { get; set; }
}
public class Item
{
public String Key { get; set; }
public String Value { get; set; }
}
Then map your data on read/write between your classes and these.
A perhaps better option would be to reshape your data when storing into:
public class Item
{
public String Name { get; set; }
public String Key { get; set; }
public String Value { get; set; }
}
Then searching for a Name by Key and Value will be a lot easier and you can still collect the Items into a single object by querying by name or by aggregating and using groupBy name as the last step in the pipeline.
This would also enabling simpler adding or removing of single items without altering large documents.

Make the right LINQ request

I have table in a database that stores the following objects:
public class MyObjInfoWebView
{
public string SerialNumber { get; set; }
public string ProductCode { get; set; }
public string Description { get; set; }
public string Certificate { get; set; }
public string Language { get; set; }
}
I also have a list of serial numbers, for example this:
var list = new List<string> {"010719/522", "010719/523", "010719/524", "010719/525", "010719/526"}
Is it possible to write (and how) LINQ query to filter objects from the table according to the available list of serial numbers and the required language?
This request solved my problem
_contex.InfoWeb.Where(x => list.Contains(x.SerialNumber) && x.Language == lang).ToListAsync();

Collapse non-repeated columns into sublist c#

I have list of objects "orginalobject" is like below and also figure . This is populated from database
orginalobject.monitorName
orginalobject.ProcessGUID
orginalobject.Apikey
orginalobject.AIRSTATION
orginalobject.variableName
orginalobject.id
orginalobject.AIRSTATIONChannel
As in Attached image you can see some columns are repeated that is
monitorName
ProcessGUID
Apikey
AIRSTATION
And non repeatable columns are
variableName
id
AIRSTATIONChannel
so I want list should be grouped by these repeating columns and other columns should become list of this object using lamda or linq
object.monitorName
object.ProcessGUID
object.Apikey
object.AIRSTATION
Object.List<Subobjects> list
And Subobjects class will be like
ObjectSubobjects.variableName
ObjectSubobjects.id
ObjectSubobjects.AIRSTATIONChannel
If I understand you question correctly, you just want to group list of objects by their non-unique monitorName, ProcessGUID, Apikey and AIRSTATION properties used as a key and for each of these groups create list of sub-objects with the remaining unique properties?
This can be done with the following simple linq query. First it uses GroupBy to create groups of originalobjects with the same values of non-unique properties. I used ValueTuple struct to represent combination of non-unique properties as a single object used as a key for grouping. But from provided image it seems that it might be superfluous and that any of the non-unique properties alone used as a grouping key should be sufficient. The rest of the query contains just two projections (Select) that copies values from originalobjects to newly created GroupObjects and ObjectSubobjects.
var groupedObjects = objects.GroupBy(o => (o.monitorName, o.ProcessGUID, o.Apikey, o.AIRSTATION))
.Select(g => new GroupObject()
{
monitorName = g.Key.monitorName,
ProcessGUID = g.Key.ProcessGUID,
Apikey = g.Key.Apikey,
AIRSTATION = g.Key.AIRSTATION,
list = g.Select(s => new ObjectSubobjects()
{
variableName = s.variableName,
id = s.id,
AIRSTATIONChannel = s.AIRSTATIONChannel
})
.ToList()
})
.ToList();
public class orginalobject
{
public string monitorName { get; set; }
public Guid ProcessGUID { get; set; }
public Guid Apikey { get; set; }
public string AIRSTATION { get; set; }
public string variableName { get; set; }
public Guid id { get; set; }
public int AIRSTATIONChannel { get; set; }
}
public class GroupObject
{
public string monitorName { get; set; }
public Guid ProcessGUID { get; set; }
public Guid Apikey { get; set; }
public string AIRSTATION { get; set; }
public List<ObjectSubobjects> list { get; set; }
}
public class ObjectSubobjects
{
public string variableName { get; set; }
public Guid id { get; set; }
public int AIRSTATIONChannel { get; set; }
}

How flatten a list with many arrays inside using LINQ

I am finding this very hard to understand and where to start, so I was hoping that some one would be able to point in the correct direction. I have a list(customers) inside which there are arrays/lists. Basically I want to flatten all the results of the list into a flat version if the list.
public class Customer : EntityBase
{
public Phonenumber[] PhoneNumbers { get; set; }
public Contact BillToContact { get; set; }
public Terms Terms { get; set; }
}
public class Contact
{
public Phonenumber[] PhoneNumbers { get; set; }
public Address Address { get; set; }
public Key Key { get; set; }
public string CompanyName { get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
}
public class Phonenumber
{
public string Number { get; set; }
public int Key { get; set; }
}
public class Terms
{
public int DueDays { get; set; }
public int DiscountDays { get; set; }
}
public class Address
{
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string Country { get; set; }
}
public abstract class EntityBase
{
public Guid Id { get; set; }
public string Status { get; set; }
public int Rev { get; set; }
}
I have tried many approaches and just keep getting more confused. So if anyone could help or even point me in the right direction I would be extremely grateful. below is one of the approaches I have tried.
public IEnumerable<Customer> Find (Func<Customer , bool> predicate) {
foreach (var p in Customer.SelectMany(p => p)) {
if(predicate(p)) {
yield return p;
}
}
}
I am Deserializing a jason string into a list but then want to display in a datagrid, but igGrid does not support binding to nested(complex) properties. So I need to flatten the list so that there is no sub levels of the list.
To select an array of PhoneNumber from List<Customer> use SelectMany:
List<Customer> customers = [data];
PhoneNumber phoneNumbers = customers.SelectMany(x=>x.PhoneNumbers).ToArray();
It's not clear at all from your question what output you actually want. Do you just want a list of all the phone numbers? Or do you want to preserve the other Customer information, such that you get multiple instances of the Customer information, each instance with a separate phone number?
You can accomplish the former with something like this:
IEnumerable<Phonenumber> numbers =
customers.SelectMany(
customer => customer.PhoneNumbers
.Concat(BillToContact.PhoneNumbers));
If you only want the Customer.PhoneNumbers numbers and not those in the BillToContact object, just leave the .Concat(BillToContact.PhoneNumbers) out of the above.
If you want to preserve one or more values from the original Customer object, you can do something like this:
var numbers = customers.SelectMany(
customer => customer.PhoneNumbers.Select(
number => new
{
Number = number,
FirstName = customer.BillToContact.FirstName,
Email = customer.BillToContact.Email
}));
The above will generate an enumeration of anonymous type objects, each having a single phone number, along with the corresponding FirstName and Email values from the associated Contact object. You can of course mix and match (e.g. use .Concat(...) to include phone numbers from the BillToContact object), and include whichever specific Customer or Contact members you want.

Trouble populating selectlist in controller code - C# MVC

I have a fairly straight forward requirement - to populate a viewmodel, which has a SelectList as one of its properties - NewOccs is defined on the model as:
public class RatesList
{
[Key]
public long TypeID { get; set; }
public string TypeName { get; set; }
public int TypeCount { get; set; }
public IEnumerable<SelectListItem> NewOccs { get; set; }
}
My controller code to populate it is:
var rooms = dbt.Rooms.Where(r => r.hotel_id == AccID)
.GroupBy(p => p.RoomTypes).Select(g => new RatesList
{
TypeName = g.Key.type_name,
TypeCount = g.Count(),
NewOccs = dbt.Rates.Where(rt => rt.type_id == g.Key.type_id).GroupBy(rt => rt.occ).AsEnumerable()
.Select(proj => new SelectListItem
{
Text = proj.Key,
Value =proj.Key
})
}).ToList();
The Rates table it should be getting its information from is:
public class Rates
{
public int id { get; set; }
public long type_id { get; set; }
public DateTime ratedate { get; set; }
public decimal rate { get; set; }
public string occ { get; set; }
}
How to I access any of the other fields in my Rates table - when I'm populating the SelectList? For example, in VSExpressIDE intellisense only allows me to type proj.Key - the other properties are not there. I want occ to be the key/value and I would like the text to be a concatenation of occ and rate - ie:
Text = proj.occ + ' ' + rate.ToString()
...but rate and occ cannot be found in intellisense.
Thank you, Mark
If you step through your debugger, you'll see that GroupBy() provides a GroupedEnumerable, which contains Keys. The keys are Lookup<string, Rates>, because you used GroupBy on a string.
If you changed your Select to a SelectMany, you'd see all your Rates. But that would defeat the purpose of the GroupBy. I'm not totally sure what you want in the end, but here is a good guide to GroupBy
Like this:
public class Client
{
public int SelectedSexId { get; set; }
public IList<Sex> SexList { get; set; }
public IList<SelectListItem> SexListSelectListItems
{
get
{
SexList=SexList??new List<Sex>();
var list = (from item in SexList
select new SelectListItem()
{
Text = item.Name,
Value = item.Id.ToString(CultureInfo.InvariantCulture)
}).ToList();
return list;
}
set { }
}
}

Categories