IEnumerable select all except string - c#

In a part of my code, I'm converting an IEnumerable list to a string.
String.Join(", ", e.User.Roles.Select(o => o.ToString()))
resolves to for example:
Admin, #everyone
This is using Discord.Net SDK where Roles is an IEnumerable containing all the 'ranks' of the user.
There's a default role that every user is apart of which I want to remove from the string. The default role can be called by using
e.Server.EveryoneRole
My idea was to use Except to filter the default role which resulted to
System.Linq.Enumerable+<ExceptIterator>d__72`1[System.Char], System.Linq.Enumerable+<ExceptIterator>d__72`1[System.Char]
or just simply filtering out #everyone is also good in my case.

Can't you just use a where, such as the following?
String.Join(", ", e.User.Roles
.Where(o => o != e.Server.EveveryoneRole)
.Select(o => o.ToString()))

Use a line Where clause.
Something like:
String.Join(", ", e.User.Roles.Select(o => o.ToString()).Where(s => s != e.Server.EveveryoneRole)

Related

Build predicate with lis in parameter

I need to filter a list on multiple value.
It works well with basic type like string but I need to filter on 2 others filters build on list like that :
predicate.And(i => i.countries.Find(c => c.Code == country).Code == country)
First of all I'm not sure it is the good way to build this sort of predicate.
Second when predicate is built it looks like that :
{i => (i.countries.Find(c => (c.Code == value(Portail.Controllers.ProfilsController+<>c__DisplayClass21_0).country)).Code == value(Portail.Controllers.ProfilsController+<>c__DisplayClass21_0).country)}
And of course it doesnt work.
Is it possible to do such a thing and if yes, how?

Nested .SelectMany statements in C# / LINQ

I have the below code which works perfectly fine:
return from fa in [...]
where fa.Flows.Any()
from f in fa.Flows
select new Flow(f.Id, f.DealingDate, f.NetCashUsd, fa.Account);
As you can see, I need Account from fa deeper down in the second select.
However I'm required to use ".Selects" instead, and this (equivalent I thought) does not work:
return [...]
.Where(fa => fa.Flows.Any())
.SelectMany(fa => fa.Flows)
.Select(f => new Flow(f.Id, f.DealingDate, f.NetCashUsd, fa.Account));
The issue here is obvious, the second .Select doesn't "know" the fa stuff anymore so can't get to Account.
(As you can probably tell by now, an "fa" has one Account and multiple Flows, and I want to turn them into "Flow"s which all have the Account assigned to them as well.)
How can I solve this using only the "." statements? I looked into different GroupBys as well but couldn't make them work either.
Thank you!
An overload of SelectMany uses an extra argument (result selector) in which you can define the returned objects. In this result selector you have access to both source item and sub item:
[....]
.SelectMany(fa => fa.Flows, (fa,f)=> new Flow(f.Id, f.DealingDate, f.NetCashUsd, fa.Account));
The equivalent would be to create an intermediate anonymous type to hold both objects.
return [...]
.SelectMany(fa => fa.Flows.Select(f => new { f, fa}))
.Select(x => new Flow(x.f.Id, x.f.DealingDate, x.f.NetCashUsd, x.fa.Account));
Also you don't need the Where since an empty Flows will just result in no selected items.

NOT IN Condition in Linq

I have a simple scenario.I want to list out all the employees except the logged in user.
Similar SQL Condition is
select * from employee where id not in(_loggedUserId)
How can I acheive the above using LINQ.I have tried the following query but not getting the desired list
int _loggedUserId = Convert.ToInt32(Session["LoggedUserId"]);
List<int> _empIds = _cmn.GetEmployeeCenterWise(_loggedUserId)
.Select(e => e.Id)
.Except(_loggedUserId)
.ToList();
Except expects argument of type IEnumerable<T>, not T, so it should be something like
_empIds = _cmn.GetEmployeeCenterWise(_loggedUserId)
.Select(e => e.Id)
.Except(new[] {_loggedUserId})
.ToList();
Also note, this is really redundant in the case when exclusion list contains only one item and can be replaces with something like .Where(x => x != _loggedUserId)
Why not use a very simple Where condition?
_empIds = _cmn.GetEmployeeCenterWise(_loggedUserId).Where(e=>e.Id != _loggedUserId).ToList();
The title of your question is how to perform a not in query against a database using LINQ. However, as others have pointed out your specific problem is better solved by a using users.Where(user => user.Id != loggedInUserId).
But there is still an answer on how to perform a query against a database using LINQ that results in NOT IN SQL being generated:
var userIdsToFilter = new[] { ... };
var filteredUsers = users.Where(user => !userIdsToFilter.Contains(user.Id));
That should generate the desired SQL using either Entity Framework or LINQ to SQL.
Entity Framework also allows you to use Except but then you will have to project the sequence to ID's before filtering them and if you need to original rows you need to fetch them again from the filtered sequence of ID's. So my advice is use Where with a Contains in the predicate.
Use LINQ without filtering. This will make your query execute much faster:
List<int> _empIds = _cmn.GetEmployeeCenterWise(_loggedUserId)
.Select(e => e.Id).ToList();
Now use List.Remove() to remove the logged-in user.
_empIds.Remove(_loggedUserId);

Combining Field Values (Name)

The following will select the name of a user who votes positively on an item and then put it in a comma separated string.
var string = string.Join(", ", comment.CommentVote.Where(v=> v.Vote == true).Select(v => v.User.FirstName).ToArray());
I want to be able to get the first and last name, put them together, and then list them out in a comma separated list.
Context: I am trying to create something similar to Facebook:
John Doe and 25 others like this
Where "25 others" provides a list of users on hover. I can loop through the users who voted and get the first and last names, concatenate them, and then add a comma, it just seems like there should be something simpler that lets me avoid the foreach loop.
Just concatenate them:
var str = string.Join(", ",
comment.CommentVote
.Where(v=> v.Vote)
.Select(v => v.User.LastName + " " + v.User.FirstName));
Besides you don't need to call ToArray() explicitly, as string.Join has an overload accepting IEnumerable<T>. And you cannot have a variable with the name string, as it's an alias for type System.String.
You can just join the to value you want in the select statement.
var results = string.Join(", ", comment.CommentVote.Where(v=> v.Vote)
.Select(v => string.Format("{0} {1}", v.User.FirstName, v.User.LastName)));
EDIT: Opps sorry, Konstantin Vasilcov already answered

Using Linq lambdas, how can I get the first item in a two-key-sorted list?

I know this is simple, but my mind is playing tricks on me right now. If we have a flat list of objects with the properties GroupSortIndex and ItemSortIndex (within the group) and we want to find the first item in the list, what's the Linq/lambda for that?
About all I can think of is (meta, not literal code...)
var soughtItem = Source.OrderBy(ItemSortIndex).OrderBy(GroupSortIndex).ToList()[0]
...but that just looks so wrong to me for some reason.
Read post : Default Extension methods to get difference between first and firstordefault
you can use FirstOrDefualt() or First() function
var soughtItem = Source.OrderBy(ItemSortIndex).
ThenBy(GroupSortIndex).FirstOrDefualt();
if(soughtItem !=null)//advantage of using firstordefault
{
}
its better to use FirstOrDefualt because if there is no data it will return null intead of excetipn
You can use IOrderedEnumerable.ThenBy (Note: an IOrderedEnumerable is returned from IEnumerable.OrderBy):
var firstItem = source.OrderBy(s => s.GroupSortIndex)
.ThenBy(s => s.ItemSortIndex)
.First();
This orders first by the group and then by the item. You should use FirstOrDefault if the sequence can be empty. Otherwise First raises an exception.
(i've assumed that you want to order first by group and then by the item instead, since the ItemSortIndex is the index of the item within the group(as mentioned))
var soughtItem = Source
.OrderBy(ItemSortIndex)
.ThenBy(GroupSortIndex).First();
If ItemSortIndex and GroupSortIndex are properties instead of functions, then you need:
var soughtItem = Source
.OrderBy(i => ItemSortIndex)
.ThenBy(i => GroupSortIndex).First();

Categories

Resources