2009-06-01 11 views
11

Czy istnieje sposób przekonwertowania kolekcji obiektów na pojedynczy nowy obiekt przy użyciu LINQ?Czy istnieje odpowiednik łańcucha LINQ.Join (ciąg, ciąg [])

Chcę użyć tego w innym wyrażeniu LINQ do SQL.

+6

You * skutecznie * poprosił o tym wcześniej dzisiaj (http://stackoverflow.com/questions/934327) - LINQ nie zmieniło od tamtego czasu –

+0

@Marc Gravell Dzięki. Jestem świadomy, że LINQ nie zmienił się w ciągu ostatniej godziny, próbowałem tylko wyjaśnić, jak wykonać konkatenację. –

+0

@ Odpowiedź Marc Gravell na (http://stackoverflow.com/questions/934327) i odpowiedź @ Skeeta poniżej są poprawne. Odpowiedzi @bruno conde i @Scott Ivey są niepoprawne. Dlatego należy oznaczyć odpowiedź @Jon Skeet jako zaakceptowaną odpowiedź. –

Odpowiedz

19

Dlaczego nie można używać string.Join sam?

string.Join("<br/>", collection.Select(e => e.TextProp).ToArray()); 
+3

Problem polega na tym, że wątpię, że zostanie to przetłumaczone na SQL. Może tak będzie - ale ja w to wątpię. Jeśli to działa, cieszę się, że całkowicie usunąłem odpowiedź :) –

+2

Po szybkim teście z linqpad nie sądzę, że zostanie to przetłumaczone na SQL. Jeśli PO potrzebuje tego do przetłumaczenia, myślę, że powinien wybrać zapisany proces, taki jak Ty lub Marc, który zasugerował. –

+0

Cholera, dlaczego tego nie widziałem. Zbudowałem własną metodę rozszerzenia, aby to zrobić i wszystko. –

7

Normalnym sposobem byłoby użyć jednego z operatorów agregacji (Aggregate, Sum, Average etc), ale całkowicie zależy od rodzaju i co chcesz robić. Jakiego rodzaju jesteś zainteresowany?

EDIT: Okay, więc chcesz połączyć ciągi ... Nie sądzę, myśleć jest coś, co zrobi to w LINQ do samego SQL. Opcje:

  • Napisz proc przechowywanej lub TVF to zrobić w SQL
  • Fetch poszczególne ciągi w LINQ to SQL i złączyć z powrotem po stronie klienta
+0

Jest to ciąg znaków, który chcę dołączyć za pomocą łańcucha separatora, np. "," lub "
". –

+0

@ OP. Dlaczego nie używać StringBuilder, jeśli tylko dodajesz ciągi? – Gishu

+0

@Jon OT Ale czy mógłbyś rzucić okiem na pytanie 926352 .. czy możesz związać luźne końce w moim rozumieniu? – Gishu

12

Można użyć metody Aggregate ...

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

lub

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

Działa to dobrze dla przeliczalnych łańcuchów, ale nie wydaje się być obsługiwane w LINQ do SQL (OP napisał, że chciał użyć tego w innym wyrażeniu LINQ do SQL): wyrzuca NotSupportedException z komunikatem "Agregat zapytania" Aggregate "nie jest utrzymany." –

3

Większość z rozwiązaniami tutaj są dość nieskuteczne, jeśli masz dużą liczbę wartości chcesz concatonate . Ponadto nie wszystkie są czytelne. Jeśli masz zamiar robić tego typu rzeczy często, to warto zbudować własną metodę rozszerzenia, aby to zrobić. Poniższa implementacja umożliwia wykonanie odpowiednika string.Join(", ", arrayOfStrings), gdzie arrayOfStrings może być IEnumerable<T>, a separatorem może być dowolny obiekt. To pozwala zrobić coś takiego:

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

Dwie rzeczy mi się podoba ten temat to:

  1. To bardzo czytelny w kontekście LINQ.
  2. Jest dość wydajna, ponieważ używa StringBuilder i unika dwukrotnego oceniania wyliczenia, co jest ważne w scenariuszu bazy danych (L2S, L2E lub 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(); 
} 
Powiązane problemy