evanmcdonnal
evanmcdonnal

Reputation: 48114

Flatten List<string[]> into single string with one line for each element

I have an instance of type List<string[]> I would to convert this to a string with a each string[] on a newline. I'm using the following LINQ query to flatten out the list however I'm not sure how I can add a new line between each string[] without expanding my query into something far more ugly. Is there a way to do it without gutting my query and using String.Join or IEnumerable.Aggregate inside a foreach loop?

results.SelectMany(x => x).Aggregate((c, n) => c + ", " + n)

Upvotes: 22

Views: 23995

Answers (3)

Tore Aurstad
Tore Aurstad

Reputation: 3826

I like to use also extension methods for this flattening of a collection of string, and also be allowed to specify a line separator. Note the use of Trim here as we will have a trailing separator at the very end otherwise.

using System.Text;

namespace MultiLingual.Translator.Lib
{
    public static class StringExtensions
    {

        /// <summary>
        /// Merges a collection of lines into a flattened string separating each line by a specified line separator.
        /// Newline is deafult
        /// </summary>
        /// <param name="inputLines"></param>
        /// <param name="lineSeparator"></param>
        /// <returns></returns>
        public static string? FlattenString(this IEnumerable<string>? inputLines, string lineSeparator = "\n")
        {
            if (inputLines == null || !inputLines.Any())
            {
                return null;
            }
            var flattenedString = inputLines?.Aggregate(new StringBuilder(),
                (sb, l) => sb.AppendLine(l + lineSeparator),
                sb => sb.ToString().Trim());

            return flattenedString;
        }

    }
}

Usage in a XUnit Test of mine :

        [Theory]
        [InlineData("Jeg er fra Norge og jeg liker brunost", "i'm from norway and i like brown cheese")]
        public async Task TranslationReturnsExpected(string input, string expectedTranslation)
        {
            string? translation = await _translateUtil.Translate(LanguageCode.English, input, LanguageCode.Norwegian);
            translation.Should().NotBeNull();
            translation.Should().BeEquivalentTo(expectedTranslation);
        }

Upvotes: 0

Sergey Berezovskiy
Sergey Berezovskiy

Reputation: 236268

String.Join(Environment.NewLine, results.Select(a => String.Join(", ", a)));

Complete sample:

var results = new List<string[]> {
    new[]{"this", "should", "be", "on"},
    new[]{"other", "line"}
};

var result = String.Join(Environment.NewLine, 
                         results.Select(a => String.Join(", ", a)));

Result:

this, should, be, on
other, line

UPDATE Here is aggregation done right - it uses StringBuilder to build single string in memory

results.Aggregate(new StringBuilder(),
                  (sb, a) => sb.AppendLine(String.Join(",", a)),
                  sb => sb.ToString());

Upvotes: 60

It&#39;sNotALie.
It&#39;sNotALie.

Reputation: 22804

results.Select(sa => sa.Aggregate((a, b) => a + ", " + b))
       .Aggregate((c, d) => c + Enviroment.NewLine + d);

Upvotes: 3

Related Questions