views:

211

answers:

5

I have a collection like this

 List<int> {1,15,17,8,3};

how to get a flat string like "1-15-17-8-3" through LINQ query?

thank you

+9  A: 

something like...

string mystring = string.Join("-", yourlist.Select( o => o.toString()).toArray()));

(Edit: Now its tested, and works fine)

Tim Jarvis
If that works...I like it. Very short, sweet, and to the point!
Andrew Siemer
This is the best answer. Note though, that the Join method used here has nothing to do with LINQ, it's a very useful method from the good old VB6 days....
andy
Sure, the linq bit is just the conversion of the Int list to a string array via a select and a toArray()
Tim Jarvis
True, but it doesn't answer how to do this through LINQ. With strings, I definitely would use this or StringBuilder, but seeing how this would be done the LINQ way would be a great introduction to using Aggregate (my solution using Aggregate is posted further down)
Charles
A: 
StringBuilder sb = new StringBuilder();

foreach(int i in collection)
{
    sb.Append(i.ToString() + "-");
}

string result = sb.ToString().SubString(0,sb.ToString().ToCharArray().Length - 2);

Something like this perhaps (off the top of my head that is!).

Andrew Siemer
+1  A: 

You can write an extension method and then call .ToString("-") on your IEnumerable object type as shown here:

int[] intArray = { 1, 2, 3 };
Console.WriteLine(intArray.ToString(","));
// output 1,2,3

List<string> list = new List<string>{"a","b","c"};
Console.WriteLine(intArray.ToString("|"));
// output a|b|c

Examples of extension method implementation are here:

http://coolthingoftheday.blogspot.com/2008/09/todelimitedstring-using-linq-and.html http://www.codemeit.com/linq/c-array-delimited-tostring.html

AndrewDotHay
+1  A: 

Use Enumerable.Aggregate like so:

var intList = new[] {1,15,17,8,3};

string result = intList.Aggregate(string.Empty, (str, nextInt) => str + nextInt + "-");

This is the standard "LINQy" way of doing it - what you're wanting is the aggregate. You would use the same concept if you were coding in another language, say Python, where you would use reduce().

EDIT: That will get you "1-15-17-8-3-". You can lop off the last character to get what you're describing, and you can do that inside of Aggregate(), if you'd like:

string result = intList.Aggregate(string.Empty, (str, nextInt) => str + nextInt + "-", str => str.Substring(0, str.Length - 1));

The first argument is the seed, the second is function that will perform the aggregation, and the third argument is your selector - it allows you to make a final change to the aggregated value - as an example, your aggregate could be a numeric value and you want return the value as a formatted string.

HTH,

-Charles

Charles
Actually I think this is what you wanted...myList.Select(o => o.ToString()).Aggregate((s1,s2) => s1 + "-" + s2);
Tim Jarvis
Aggregate is a good answer, but I personally find its harder to understand than a simple string.join() (just my own personal pref)
Tim Jarvis
I second Tim J, thats how I prefer to do it.
ccook
If the list contains many elements then all those string concatenations will affect the performance. You could use a StringBuilder for the accumulator instead.
LukeH
(By the way, your second version will throw an exception if the list is empty.)
LukeH
@Tim: Nope `string result = intList.Aggregate(string.Empty, (str, nextInt) => str + nextInt + "-");` is correct. str is the "running total" - what's been aggregated thus far.
Charles
@Luke: Good catch. You could check before hand, or use something like `str.Length - 1 > 0 ? : str.Length - 1 : 0` - but that's pretty ugly.
Charles
@Charles: Or, slightly less ugly: `Math.Max(str.Length - 1, 0)`
LukeH
A: 

The best answer is given by Tim J.

If, however, you wanted a pure LINQ solution then try something like this (much more typing, and much less readable than Tim J's answer):

string yourString = yourList.Aggregate
    (
        new StringBuilder(),
        (sb, x) => sb.Append(x).Append("-"),
        sb => (sb.Length > 0) ? sb.ToString(0, sb.Length - 1) : ""
    );

(This is a variation on Charles's answer, but uses a StringBuilder rather than string concatenation.)

LukeH