Say that for debugging purposes, I want to quickly get the contents of an IEnumerable into one-line string with each string item comma-separated. I can do it in a helper method with a foreach loop, but that's neither fun nor brief. Can Linq be used? Some other short-ish way?
using System;
using System.Collections.Generic;
using System.Linq;
class C
{
public static void Main()
{
var a = new []{
"First", "Second", "Third"
};
System.Console.Write(string.Join(",", a));
}
}
string output = String.Join(",", yourEnumerable);
String.Join Method (String, IEnumerable
Concatenates the members of a constructed IEnumerable collection of
type String, using the specified separator between each member.
collection.Aggregate("", (str, obj) => str + obj.ToString() + ",");
(a) Set up the IEnumerable:
// In this case we are using a list. You can also use an array etc..
List<string> items = new List<string>() { "WA01", "WA02", "WA03", "WA04", "WA01" };
(b) Join the IEnumerable Together into a string:
// Now let us join them all together:
string commaSeparatedString = String.Join(", ", items);
// This is the expected result: "WA01, WA02, WA03, WA04, WA01"
(c) For Debugging Purposes:
Console.WriteLine(commaSeparatedString);
Console.ReadLine();
IEnumerable<string> foo =
var result = string.Join( ",", foo );
to join large array of strings to a string, do not directly use +, use StringBuilder to iterate one by one, or String.Join in one shot.
Related
I have a list that I traverse as follows:
foreach (var obj in mylist)
{
return += obj.Value.ToString() + ";";
}
This doesn't seem to work. Do I need a StringBuilder?
You could just use string.Join
Concatenates the elements of a specified array or the members of a
collection, using the specified separator between each element or
member.
and Enumerable.Select
Projects each element of a sequence into a new form.
return string.Join(";", mylist.Select(x => x.Value));
Your solution is not working because you are concatenating your string with return which is keyword in C#.
Initialize StringBuilder append your value to it with semicolon.
Like,
StringBuilder sb = new StringBuilder();
foreach (var obj in mylist)
{
sb.AppendFormat("{0};", obj.Value);
}
return sb.ToString();
Elegant way is to use string.Join() where you pass string with an IEnumerable #TheGeneral gave you solution to use string.Join() i.e.
var result = string.Join(";", mylist.Select(x => x.Value));
where ; is your separator and mylist.Select() will return IEnumerable of Values which will return same result as your first approach.
I have a list of strings where I need to sort it by the ending substring. For example, assume we have these strings in the list:
Get_USER_By_ID
Get_Product_By_Name
Get_Product_By_ID
Get_Location_By_Name
...
I Need to sort it so that all the functions matching the same By_ are after each other
I could loop over the list, and create many new lists, and if the string contains a specific string (i.e. By_ID), I add it to its related List.
I want to sort them in the same list (same as if I say sort ascending or descending for instance) rather than creating many new lists (in my case I have to create 9 new lists)
You could create Custom Comparer. IComparer defines how to compare objects of type T. This could be used with List.Sort for customized Sorting of the collection. For example, for the input collection
var strList = new List<string>
{
"Get_USER_By_ID",
"Get_Product_By_Name",
"Get_Product_By_ID",
"Get_Location_By_Name"
};
You could sort by
strList.Sort(new CustomStringComparer());
Or using Linq
var result = strList.OrderBy(x=>x,new CustomStringComparer());
Where CustomStringComparer is defined as
public class CustomStringComparer : IComparer<string>
{
private Regex _regex = new Regex(#"By_(?<Tag>[\S]*)",RegexOptions.Compiled);
public int Compare(string first, string second)
{
var firstSubString = _regex.Match(first).Groups["Tag"].Value;
var secondSubString = _regex.Match(second).Groups["Tag"].Value;
return firstSubString.CompareTo(secondSubString);
}
}
Ouput
Get_USER_By_ID
Get_Product_By_ID
Get_Product_By_Name
Get_Location_By_Name
myList = myList.OrderBy(str => str.Split(new[] {"By_"}, StringSplitOptions.None)
.Last()).ToList();
Is there a better—more functional, succinct, or elegant—way to write this? A reduce/fold function, perhaps?
var key = String.Join(String.Empty,
new[] {
keyRoot,
controllerName,
actionName
}.Concat(
from param in params
select param.Key + param.Value
)
);
The input is a few variables that are strings, as well as an enumerable of concatenated keys/values from a Dictionary<string, string>.
The output should be all of these strings concatenated.
It sounds like you could use the LINQ Aggregate function:
Using LINQ to concatenate strings
More readable to me would be something like this:
string key = string.Format("{0}{1}{2}{3}",
keyRoot,
controllerName,
actionName,
string.Join(string.Empty, parameters.Select( p => p.Key + p.Value)));
This might not be as "functional" but certainly as succinct and clear as I can come up with.
This doesn't improve it much...
var key = string.Concat(
new[] {
keyRoot,
controllerName,
actionName
}.Concat(
params.Select(kvp) => param.Key + param.Value)
).ToArray ()
);
This is 2 lines shorter if it doesn't have to be a single statement.
var list = new List<String> {
keyRoot,
controllerName,
actionName
};
list.AddRange (params.Select(kvp) => param.Key + param.Value));
var key = string.Concat(list.ToArray ());
I think for concatenating the sequence of all strings, your construct is already as functional as you can get.
Instead of using String.Join with an empty string, I'd probably use a StringBuilder together with a ForEach extenstion method like
public static class MyExtensions {
public static void ForEach(this IEnumerable<T> enumerable, Action<T> action) {
foreach (var entry in enumerable)
action(entry);
}
}
I also would define a local variable for the sequence like
var seq = new[] {
keyRoot,
controllerName,
actionName
}.Concat(
from param in params select param.Key + param.Value
);
var sb = new StringBuilder();
seq.ForEach(s=>sb.Append(s));
Of course, using the Aggregate function would be more "functional", but it is not more readable in my opinion plus it has performance penalties, because you need to construct intermediate strings...
With an extension to StringBuilder:
public static class StringBuilderExtensions {
public static StringBuilder AppendAll(this StringBuilder builder, IEnumerable<string> strings) {
foreach (string s in strings) builder.Append(s);
return builder;
}
}
it gets rather short and efficient:
string key =
new StringBuilder()
.Append(keyRoot)
.Append(controllerName)
.Append(actionName)
.AppendAll(parameters.Select(p => p.Key + p.Value))
.ToString();
This will build the string without creating any intermediate arrays.
One thing to improve would be to avoid the intermittent strings p.Key + p.Value by adding the key and value directly to the StringBuilder, but then the code gets less reusable.
Another thing to improve would be to set the capacity of the StringBuilder, but then you would need to loop though the dictionary and add upp the length of the strings first.
(Note: I used parameters for the name of the dictionary instead of params, as that is a keyword.)
Here is a solution in one expressions using Aggregate (effectively a fold):
var key = params.Aggregate(new StringBuilder()
.Append(keyRoot)
.Append(controllerName)
.Append(actionName),
(sb, p) => sb.Append(p.Key).Append(p.Value))
.ToString();
I have List consists of {"a","b","c"} i have string s contains{"alphabets"} .i like to add the list to string. i need final output in s like this `{"alphabetsabc"}. i like to do this using linq.
Using LINQ, or even Join, would be overkill in this case. Concat will do the trick nicely:
string s = "alphabets";
var list = new List<string> { "a", "b", "c" };
string result = s + string.Concat(list);
(Note that if you're not using .NET4 then you'll need to use string.Concat(list.ToArray()) instead. The overload of Concat that takes an IEnumerable<T> doesn't exist in earlier versions.)
Why not just string.Join? Using Linq would be an overkill.
Quick & dirty:
List<string> list = new List<string>() {"a", "b", "c"};
string s = "alphabets";
string output = s + string.Join("", list.ToArray());
You need the Aggregate method, if you really want to use LINQ.
Say I have a List of objects, and the object has a string property. I want to get a single comma-separated list of the value of each string property of each object in the list.
Here's 1 way to do it (sans linq)
StringBuilder result = new StringBuilder()
foreach(myObject obj in myList)
{
result.Append(obj.TheString);
result.Append(", ");
}
// then trim the trailing ", " and call ToString() on result, etc, etc...
Here's my first shot at linqification. Is there a better way?
string result = string.Join(", ", myList.Select(myObj => myObj.TheString).ToArray());
That's one line of code, but it doesn't look very efficient to me -- iterate the list just to build an array, just to iterate the array and build a string... whew!
Is there a better way?
If you want efficient, use Enumerable.Aggregate with StringBuilder:
string result = myList.Aggregate(new StringBuilder(),
(sb, o) => sb.Append(o.TheString).Append(", "))
.ToString();
The original problem is that String.Join wants an array. In .NET 4, there will be an overload that takes IEnumerable<string> (and I expect it will be implemented like above).
I like this extension method for joining strings. It's basically the same technique you are using, but wrapped in an extension method. I wouldn't recommend it for large sets since efficiency was not the goal. The benefit to me is expressiveness (very linqy) and convenient for small sets:
[Test]
public void Should_make_comma_delimited_list()
{
var colors = new List<HasColor>
{
new HasColor { Color = "red" },
new HasColor { Color = "green" },
new HasColor { Color = "blue" }
};
var result = colors.Implode(x => x.Color, ", ");
Assert.That(result, Is.EqualTo("red, green, blue"));
}
public class HasColor
{
public string Color { get; set; }
}
public static class LinqExtensions
{
public static string Implode<T>(this IEnumerable<T> list, Func<T, string> func, string separator)
{
return string.Join(separator, list.Select(func).ToArray());
}
}
Use string.Join, it's good enough.
Optimize when profiler will tell you to do so.
Readability of the version with StringBuilder is poor and you are still getting your trailing comma.
Here's another way (result is a StringBuilder):
myList.ForEach(
myObj =>
{
if (result.Length != 0)
result.Append(",");
result.Append(myObj.TheString);
}
);