19

Is there any way to convert a collection of objects into a single new object using LINQ?

I want to use this within another LINQ to SQL expression.

Matthew Dresser
  • 11,273
  • 11
  • 76
  • 120
  • 6
    You *effectively* asked this earlier today (http://stackoverflow.com/questions/934327) - LINQ hasn't changed since then – Marc Gravell Jun 01 '09 at 12:51
  • @Marc Gravell Thanks. I'm aware that LINQ has not changed within the last hour or so, I was just trying to get clarification about how to do the concatenation. – Matthew Dresser Jun 01 '09 at 13:01
  • @Marc Gravell's answer on (http://stackoverflow.com/questions/934327) and @Jon Skeet's answer below are correct. @bruno conde's and @Scott Ivey's answers are incorrect. Therefore, you should mark @Jon Skeet's answer as the accepted answer. – Jim G. Feb 04 '10 at 17:11
  • Another question almost _exactly_ the same has been asked today. What is the world coming to? http://stackoverflow.com/questions/993534 – Callum Rogers Apr 18 '10 at 14:56

4 Answers4

28

Why don't you use the string.Join itself?

string.Join("<br/>", collection.Select(e => e.TextProp));
Community
  • 1
  • 1
bruno conde
  • 47,767
  • 15
  • 98
  • 117
  • 7
    The problem is that I doubt that will be translated into SQL. Maybe it will - but I doubt it. If it works, I'm happy just to remove my answer entirely :) – Jon Skeet Jun 01 '09 at 13:03
  • 4
    After a quick test with linqpad I don't think this gets translated to SQL. If the OP needs this to be translated I think he should opt on a stored proc like you or Marc have suggested. – bruno conde Jun 01 '09 at 13:19
  • Dammit why didn't I see this. I built my own extension method to do this and everything. – Callum Rogers Apr 18 '10 at 14:52
  • Great answer, and you do not need to call ToArray() since Join() can accept an enumerable. – Gen1-1 May 14 '21 at 20:41
14

You can use the Aggregate method...

var myResults = (from myString in MyStrings
                 select myString)
                .Aggregate(string.Empty, (results, nextString) 
                   => string.Format("{0}<br />{1}", results, nextString));

or

var myResults = MyStrings.Aggregate(string.Empty, (results, nextString) 
                   => string.Format("{0}<br />{1}", results, nextString));
Scott Ivey
  • 40,768
  • 21
  • 80
  • 118
  • 7
    This works fine for enumerable of strings, but does not seem to be supported in LINQ to SQL (OP wrote he wanted to use this within another LINQ to SQL expression): it throws NotSupportedException with message "The query operator 'Aggregate' is not supported." – Sergii Volchkov Apr 10 '16 at 18:25
9

The normal way would be to use one of the aggregation operators (Aggregate, Sum, Average etc), but it entirely depends on the type and what you want to do. What type are you interested in?

EDIT: Okay, so you want to concatenate strings... I don't think there's anything which will do that in LINQ to SQL itself. Options:

  • Write a stored proc or TVF to do it in SQL
  • Fetch the individual strings in LINQ to SQL and concatenate back on the client side
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • It's string, and I want to append using a separator string e.g. ", " or "
    ".
    – Matthew Dresser Jun 01 '09 at 12:47
  • @ OP. Why not use StringBuilder if you're just appending strings? – Gishu Jun 01 '09 at 12:53
  • @Jon OT But could you take a look at question 926352.. can you tie up the loose ends in my understanding? – Gishu Jun 01 '09 at 12:54
  • 2
    Just so poeple know using a custom aggregate function works in LINQ to ENTITIES but not in LINQ to SQL. Table value functions work in neither. The only workaround I could come up with was to create a view. – Michael May 26 '11 at 01:01
8

Most of the solutions here are fairly inefficient if you have large numbers of values you want to concatonate. Also, they're not all that readable. If you are going to do this sort of thing frequently, then it's worth building your own extension method to do it. The implementation below allows you to do the equivalent of string.Join(", ", arrayOfStrings) where the arrayOfStrings can be an IEnumerable<T>, and separator can be any object at all. It allows you to do something like this:

var names = new [] { "Fred", "Barney", "Wilma", "Betty" };
var list = names
    .Where(n => n.Contains("e"))
    .Join(", ");

Two things I like about this are:

  1. It's very readable in a LINQ context.
  2. It's fairly efficient because it uses StringBuilder and avoids evaluating the enumeration twice which is important in a database scenario (L2S, L2E, or L2Nh).
public static string Join<TItem,TSep>( 
    this IEnumerable<TItem> enuml, 
    TSep                    separator) 
{ 
    if (null == enuml) return string.Empty; 

    var sb = new StringBuilder(); 

    using (var enumr = enuml.GetEnumerator()) 
    { 
        if (null != enumr && enumr.MoveNext()) 
        { 
            sb.Append(enumr.Current); 
            while (enumr.MoveNext()) 
            { 
                sb.Append(separator).Append(enumr.Current); 
            } 
        } 
    } 

    return sb.ToString(); 
}
Damian Powell
  • 8,655
  • 7
  • 48
  • 58