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
Related
I have this query so far:
var msg = ModelState.Values
.Where(x => x.Errors.Any())
.Select(c => c.Errors.Select(d => d.ErrorMessage).Aggregate((e, f) => (e ?? "") + "<br/>" + f))
.Aggregate((x, y) => (x ?? "") + "<br/>" + y);
This is working perfectly, but I need to filter out the duplicate error messages. I have tried adding both GroupBy() and Distinct() to several places both prior to and following the predicate that obtains the ErrorMessage. What am I missing?
If I run this as it is, I receive the following result:
"Contact Email address invalid<br/>Contact Email address invalid"
Each ErrorMessage value here is "Contact Email address invalid". These are the duplicates that I would like to filter out.
Can I suggest an alternative?
Assuming you want distinct messages, separated by the break tag:
var items = ModelState.Values
.SelectMany(c => c.Errors.Select(d => d.ErrorMessage))
.Distinct()
.ToArray();
string msg = string.Join("<br/>", items);
The problem is that you've got two places producing values. Consider the following case:
Value Errors
1. "Bad username", "Contact Email address invalid"
2. "Contact Email address invalid"
Even if you add Distinct to both Select calls, it won't do what you want, as Bad username<br/>Contact Email address invalid will be compared to Contact Email address invalid, will be found not to be equal, and will be aggregated into Bad username<br/>Contact Email address invalid<br/>Contact Email address invalid, which, I assume, is not what you want.
Instead, you should be flattening the nested lists of errors first. This is the job of SelectMany. To flatten your list, you just need to do:
var errorMessages = ModelState.Values
.Where(x => x.Errors.Any())
.SelectMany(c => c.Errors.Select(d => d.ErrorMessage))
Now errorMessages is a list of every error message from every Value. (Note that the Where is probably unneeded: Select or SelectMany on an empty sequence is a no-op.)
Now there is the second issue:
It is almost always bad practice to use + with strings in C#, due to string's immutablity. Instead, you want to use string.Join, string.Format, or StringBuilder depending on if your input is a sequence, multiple variables or longer strings. In this case you have an array, so string.Join is the tool of choice:
var msg = string.Join("<br/>", errorMessages.Distinct())
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)
Consider the following csv
string data = "Hey, Bob, How are you";
I can flatten it to:
"Hey; Bob; How are you"
Using the following:
var s = String.Join("; ",data.Split(',').Select(d => d.Trim()).ToArray());
Is there any way I can get the index of the current item in the join and append it to the resulting string? To produce somthing along the lines of:
"Hey=0; Bob=1; How are you=2"
Does linq facilitate anything like this? Perhaps combined with a String.Format() type method?
Here try this there is an index selector in the select you can use it to concatonate with each of your data pieces
var s = String.Join("; ",data.Split(',')
.Select((d, i) => d.Trim() + "= " + i.ToString()).ToArray());
Sure - just change your Select slightly:
var s = String.Join("; ",data.Split(',')
.Select((d, i) => String.Format("{0}={1}",d.Trim(),i)));
note that string.Join can take an IEnumerable<T> so there's no need to call ToArray.
if (DataList.Any(item => item.ID == int.Parse(Txtbox2.Text)))
{
Txtbox1.Text += string.Join(";", DataList.Select(o => o.DataString()));
}
I am trying to get the list into a textblock but only the items that meet a certain criteria.
The only thing I have is it displaying the whole list when the IF is met, is the any way for me to put a condition in the part that actually makes the list?
EDIT: all the DataString method is, is a method in the Data Class that converts all the vairous data types into a string output.
You want to use Where, rather than Any:
int value = int.Parse(Txtbox2.Text); //consider using TryParse here
var strings = DataList.Where(item => item.ID == value)
.Select(item => item.DataString());
Txtbox1.Text += string.Join(";", strings);
Also note that rather than parsing the textbox value over and over again, it's worth parsing it once and storing the result in a variable.
My values come from ComboBox:
2|722|742|762|77
I delete unnecessary characters as follows:
foreach (var item in checkListBox)
{
string[] list = item.Split(
new string[] { "2|" },
StringSplitOptions.RemoveEmptyEntries);
}
My list values result:
"72"
"74"
"76"
"77"
My question is:
how can I get all of the above values in 1 row (next to each other) separated by comma like this:
72,74,76,77
?
It sounds like you just want string.Join:
string commaSeparated = string.Join(",", list);
(Note that this is not part of LINQ - it's not the same kind of "join" as for joining multiple sequences. It's joining several strings together with a separator.)
While you can do this in a single statement as per the currently accepted answer, I'd personally consider leaving your existing statement and having this as a separate step. It makes the code easier to both read and debug.
String.Join(",",list);
Though: a) This is not Linq. b) As is mentioned in another answer here - It would be simpler in this case to use Replace.
Using Linq:
list.Select(s => s + ",").Aggregate((s, q) => s + q).TrimEnd(',');
How about
var result = string.Join(",", item.Split(new string[] { "2|" }, StringSplitOptions.RemoveEmptyEntries));
Just use Replace directly:
string input = "2|722|742|762|77";
var result = input.Replace("2|",",").Trim(',');
As noted in the other answers, string.Join is what should be used here. If you'd however insist on LINQ:
var result = list
.Skip(1)
.Aggregate(
list.FirstOrDefault() ?? string.Empty,
(total, current) => total + "," + current);