Count the number of element present in the inner list - c#

public Class Users
{
string UserName,
List<UserDesktop> userDesktop
}
public class UserDesktop
{
int ID,
string DesktopName,
string type -- here Type value is A, B;
}
Here I have to find the users count having desktop assigned of type A
Users variable containing all data.
List<Users> finalUsers = users.Count(s=>s.userDesktop.where(x=>x.type == "A"))
Please let me know the correct way of doing it.

You might want to use SelectMany to flatten the list then count it:
int numberOfUsersWithDesktopOfTypeA = users.SelectMany(u => u.userDesktop)
.Count(ud => ud.type == "A");
If you want the list of users that have an A desktop:
var usersWithDesktopA = Users.Where(u => u.Any(ud => ud.type == "A"));
var numberOfUsersWithDesktopA = usersWithDesktopA.Count();

To query the user(s) who has UserDesktop of type 'A':
List<Users> hasDesktopAUsers = users.Where(u => u.userDesktop.Any(ud => ud.type == "A"))
.ToList();
Next, you can get the number of count from the previous result as:
int numberOfDesktopAUsers = hasDesktopAUsers.Count;
Out of topic:
It is recommended to have a proper naming convention for handling single and plural terms to avoid confusion. For example:
public class User
{
public string UserName { get; set; }
public List<UserDesktop> UserDesktops { get; set; }
}
public class UserDesktop
{
public int ID { get; set; }
public string DesktopName { get; set; }
public string Type { get; set; }
}
From the above, you should name as User as it is an User object while UserDesktops with 's' as it is a collection set.
Final solution:
List<User> hasDesktopAUsers = users.Where(u => u.UserDesktops.Any(ud => ud.Type == "A"))
.ToList();
int numberOfDesktopAUsers = hasDesktopAUsers.Count;

Related

linq select from list remove other rows where condition

I have a list like this
public class RolesAccessModel
{
public int Id { get; set; }
public string PrimaryMenu { get; set; }=string.Empty;
public string OptionMenu { get; set; } = string.Empty;
public string Roles { get; set; } = string.Empty;
public string UserType { get; set; } = string.Empty;
}
The data I have in the list is like this
1,'PR','A','R','U'
2,'PR','A','R','U2'
3,'PR','A','R1','U5'
4,'PR','A','R1','U3'
5,'PR','A','R2','U6'
6,'PR','A','R2','U4'
I have 2 or more UserType values for the shortlist (PrimaryMenu, OptionMenu, Role)
I need to retrieve the shortlist (PrimaryMenu, OptionMenu, Role) where UserType is different from a specific value...
Using Linq I have this
List<RolesAccessModel> result = roleAccess.Where(p => p.UserType!= 'U').ToList();
It retrieves all list except ID=1
But I need to remove also the shortlist (PrimaryMenu, OptionMenu, Role) of that UserType. So ID=2 also has to be remove.
One approach is to get a list that contains the ID I want to delete, and then Exclude from the first list... the second list.
But I would like to do in just Linq operation...
It is that possible?
Try:
List<RoleAccessModel> result = roleAccess.Where(p =>
p.UserType != 'U'
&& !roleAccess
.Where(p2 => p2.UserType == 'U')
.Select(p2 => p2.Roles)
.Contains(p.Roles)).ToList();
I'd approach this with grouping:
roleAccess
.GroupBy(p => (p.PrimaryMenu, p.OptionMenu, p.Roles))
.Where(g => !g.Any(p => p.UserType == "U"))
.SelectMany(g => g)
.ToList();

How can I update the contents of a list with data from another list?

I have a list of two properties named Kanjis :
and I would like to use that to update the contents of another list named PhraseSources
public class PhraseSource
{
[PrimaryKey]
public string Id { get; set; }
public int PhraseNum { get; set; }
public string English { get; set; }
public string Kanji { get; set; }
public string WordType { get; set; }
public string FrequencyA { get; set; }
}
by matching together Kanji > Text and updating FrequencyA with Code
Is this something that can be done with LINQ or is there a better to way to do this by iterating through each of the rows of the phraseSource, checking for a matching entry in Kanjis and doing an update that way?
Here's the code suggested by Salva that I tried:
(from sa in source
join d in psDb on sa.Text equals d.Kanji
let temp = d.FrequencyA = sa.Code
select 0).ToList();
gives error:
ApplyFrequency.cs(14,14): Error CS1941: The type of one of the
expressions in the join clause is incorrect. Type inference failed in
the call to 'Join'. (CS1941) (Download)
source.Join(psDb, s => s.Text, d => d.Kanji, (s, d) => d.FrequencyA = s.Code).ToList();
gives error:
ApplyFrequency.cs(21,21): Error CS0411: The type arguments for method
'Enumerable.Join(IEnumerable,
IEnumerable, Func, Func,
Func)' cannot be inferred from the usage. Try
specifying the type arguments explicitly. (CS0411) (Download)
Notes:
I had to use this code as I was asked to change FrequencyA to an int:
var source = original
.Select(x => new
{
Text = x.Text,
Code = Convert.ToInt32(x.Code.Substring(2))
})
.ToList();
You can do it via single linq query syntax:
var source = new List<TextCodeClass>();
var dest = new List<PhraseSource>();
(from s in source
join d in dest on s.Text equals d.Kanji
let temp = d.FrequencyA = s.Code.ToString()
select 0).ToList();
or via method syntax:
source.Join(dest, s => s.Text, d => d.Kanji, (s, d) => d.FrequencyA = s.Code.ToString())
.ToList();
You can update list through LINQ only. The closest you could get is:
static void Main(string[] args)
{
List<SomeClass> scl = new List<SomeClass>();
List<OtherClass> ocl = new List<OtherClass>();
foreach (var item in scl)
item.FrequencyA = ocl.Where(i => i.Text == item.Kanji).FirstOrDefault()?.Code ?? null;
}
// sample classes that reflect relevant properties
public class SomeClass
{
public string FrequencyA { get; set; }
public string Kanji { get; set; }
}
public class OtherClass
{
public string Code { get; set; }
public string Text { get; set; }
}

Lambda Expression for Finding properties

I want to retreive LineOfBusiness property from promotionCatalogResponseRootObject where PromotionID is equal to myId
public class PromotionCatalogResponseRootObject
{
public PromotionCatalogResponse PromotionCatalog { get; set; }
}
public class Promotion
{
public string PromotionId { get; set; }
public string LineOfBusiness { get; set; }
public string PromotionName { get; set; }
}
public class PromotionCatalogResponse
{
public List<Promotion> Promotion { get; set; }
}
I started off like this but I know I'm doing it wrong. Please guide
string myId = "7596";
string lineOfBusiness = dataPromotionCatalog.PromotionCatalog
.Promotion.Find(p => p.LineOfBusiness);
What you are missing is the the Find method is expecting to receive a predicate with a bool return value but you are returning a string, the LineOfBusiness property.
First filter the items you want and then select the desired property. In addition, I'd go with the Where instead of the Find. (Find() vs. Where().FirstOrDefault())
var result = dataPromotionCatalog.PromotionCatalog.Promotion
.Where(i => i.PromotionId == myId)
.Select(i => i.LineOfBusiness);
or in query syntax
var result = (from item in dataPromotionCatalog.PromotionCatalog.Promotion
where item.PromotionId == myId
select item.LineOfBusiness);
If you are expecting/want to have one item then use FirstOrDefault:
var result = dataPromotionCatalog.PromotionCatalog.Promotion
.FirstOrDefault(i => i.PromotionId == myId)?.LineOfBusiness;

C# Web API DTO combining two Objects in MVC

Hi I'm a newbie to C# and DTO's and I'm looking for a bit of advice in writing a method. Basically I have two transfer objects, Members and Source. What I'm trying to achieve is display a list of Members from a specific Source.
The only problem is I need to be able to display Members associated with a SourceId from a SourceRef. As I dont want to pass the sensitive MemberID and SourceId so each has a reference id and thats how I will be identifying them in my API
Member Object
public class MemberObj
{
public int memId { get; set; }
public String memRef { get; set; }
public String fName { get; set; }
public String lName { get; set; }
public String email { get; set; }
public String detail { get; set; }
public int sourceId { get; set; }
}
Source Object
public class SourceObj
{
public int sourceId { get; set; }
public String sourceRef { get; set; }
}
So I would like to go to the address for example
http://..../api/Member/Source/{sourceRef}
and display the list of Members associated to the sourceId via the sourceRef
I came up with something along these lines....
public IEnumerable<MemberObj> GetMem(String code)
{
var sc = db.Sources;
var thisSrc = sc.Where(s => s.sourceRef == code).SingleOrDefault();
return db.Members.Select(s => new MemberObj
{
memId = s.memId,
firstName = s.firstName,
lastName = s.lastName,
email = s.emailAddress,
memRef = s.memRef
}).AsEnumerable().Where(s => s.sourceRef== thisSrc.sourceRef);
But this returns nothing.
The following accepts code as the sourceRef and returns the SourceID that the ref corresponds too.
From here, it simply filters all members to only the ones with the matching sourceID. (I don't have a copy of VS near me so the syntax may be out! If only Notepad++ had intelisense...)
public IEnumerable<MemberObj> GetMem(String code)
{
int soureID = db.Sources.Where(s => s.sourceRef == code).SingleOrDefault().sourceID; //I'm assuming code is the source ref??
//Insert and handle your sourceID == 0 checks here.
//...
return db.Members.Where(m => m.sourceId == sourceID);
}
This should work:
public IEnumerable<MemberObj> GetMem(String code)
{
var thisSrc = db.Sources
.Where(s => s.sourceRef == code)
.SingleOrDefault();
if(thisSrc == null)
return Enumerable.Empty<MemberObj>();
return db.Members.Where(m => m.sourceId == thisSrc.sourceId);
}
Take in account, that you should handle the case when there are more than one source by given code (SingleOrDefault throws an exception in that case.)
If you are sure that is not a case use FirstOrDefault instead.
Just building into Hamlet's answer, you could do something like this to return a DTO instead of your Member Entity:
public IEnumerable<MemberDTO> GetMem(String code)
{
//Get the source object by sourceRef
var thisSrc = db.Sources
.Where(s => s.sourceRef == code)
.SingleOrDefault();
if(thisSrc == null)
return Enumerable.Empty<MemberObj>();
//Filter Members by sourceId and map the results to a MemberDTO with less fields
var data = (from m in db.Members
where m.sourceId == thisSrc.sourceId
select new MemberDTO
{
MemberId = m.memId,
//map the rest of your DTO fields..
}).ToList();
return data;
}

Convert IGrouping from one class to another using linq

I have two classes Teams and PlayerTeams
public class PlayerTeams
{
public int ID { get; set; }
public string PlayerName { get; set; }
public string PlayerCountry { get; set; }
public bool IsActive { get; set; }
public string PlayerTeam { get; set; }
}
public class Players
{
public int ID { get; set; }
public string Name { get; set; }
public string Country { get; set; }
public bool? Status { get; set; }
}
I have a list of PlayerTeams which is grouped by PlayerTeam like this.
var groupedPlayers = teams
.OrderBy(x => x.PlayerName)
.GroupBy( x => x.PlayerTeam)
.ToList();
Its of type List<IGrouping<string, PlayerTeams>> but I want it to be of type List<IGrouping<string, Players>> as I do not want the redundant key information on every row.
How could I possibly achieve that? I could only think of something like .ConvertAll() on the IGrouping. I am not able to make it also.
Is there an efiicient way to do this?
If you can change the grouping, I'd just use:
var groupedPlayers = teams
.OrderBy(x => x.PlayerName)
.GroupBy(x => x.PlayerTeam, Players.FromPlayerTeam)
.ToList();
Where Players.FromPlayerTeam is a static method in Players which takes a PlayerTeam and returns a Players.
Additionally, I'd suggest using ToLookup instead of GroupBy - a Lookup is exactly what you want here, without bothering with the ToList call.
This not testet, just an idea.
If you have trouble converting your linq statement, which is expecting the IGrouping type, to a string list, then you might have to select it before.
var groupedPlayers = new List<string>();
groupedPlayers = teams
.OrderBy(x => x.PlayerName)
.GroupBy(x => x.PlayerTeam, Players.FromPlayerTeam)
.Select(x => x.Key) // << added select
.ToList();

Categories

Resources