0

Lets say i have a string array like this,

string[] array1 = { 
    "<p>here is a big sentence</p>",
    "file1",
    "file2",
    "<p>this is a big paragraph</p>",
    "file3",
    "file4",
    "file5",
    "<p>this is another paragraph</p>",
    };

i want to convert this to,

string[] array2 = { 
    "<p>here is a big sentence</p>",
    "file1,file2",
    "<p>this is a big paragraph</p>",
    "file3,file4,file5",
    "<p>this is another paragraph</p>",
    };

i need to concat strings, inside an array, based on a condition, that they don't have a <p></p> tag.

what is cleanest way to do this, is there a correct way to do this? with or without linq?

4
  • 3
    Have you made any effort to solve this yourself? Commented Aug 6, 2024 at 9:14
  • I have a small nuget package called "linqy", with which you could do this with a one-liner: var array2 = array1.GroupIf((s1, s2) => !s1.StartsWith("<p>") && !s2.StartsWith("<p>")).Select(g => string.Join(", ", g)).ToArray(); Commented Aug 6, 2024 at 9:31
  • 2
    The correct way to do this is probably to use some kind of HTML parser. Commented Aug 6, 2024 at 10:32
  • @ProgrammingLlama i did try to think about a solution before posting, and my ideas are quite close to 2 of the answers posted, i posted this question to make sure that i am not missing some basic pattern for this kind of problem, trying to find different ways to approach this problem, maybe some would be more efficient than others.
    – sharp12345
    Commented Aug 6, 2024 at 11:06

4 Answers 4

4

A somewhat general solution would be to write a GroupStrings() method which groups the strings into arrays according to a supplied predicate:

public static IEnumerable<string[]> GroupStrings(IEnumerable<string> strings, Predicate<string> shouldBeGrouped)
{
    var group = new List<string>();

    foreach (var s in strings)
    {
        if (shouldBeGrouped(s))
        {
            group.Add(s);
        }
        else
        {
            if (group.Count > 0)
            {
                yield return group.ToArray();
                group.Clear();
            }

            yield return [s];
        }
    }

    if (group.Count > 0)
    {
        yield return group.ToArray();
    }
}

Then you can create the required resulting array by calling that as follows:

var groups = GroupStrings(array1, s => !s.StartsWith("<p>") || !s.EndsWith("</p>"));
var array2 = groups.Select(group => string.Join(",", group));
3

Iterator blocks are often useful when you want to write some more complicated LINQ-type functionality. Something like this for example:

public static IEnumerable<string> MyIteratorBlockMethod(IEnumerable<string> source)
{
    var sb = new StringBuilder();
    foreach (var s in source)
    {
        if (s.Contains("<p>")) // or whatever condition you want
        {
            if (sb.Length > 0)
            {
                yield return sb.ToString();
                sb.Clear();
            }

            yield return s;
        }
        else
        {
            if (sb.Length > 0)
            {
                sb.Append(',');
            }

            sb.Append(s);
        }
        
    }
   if (sb.Length > 0){
      yield return sb.ToString();
   }
}

Use like

[Test]
public void MergeTest()
{
    string[] array1 = {
        "<p>here is a big sentence</p>",
        "file1",
        "file2",
        "<p>this is a big paragraph</p>",
        "file3",
        "file4",
        "file5",
        "<p>this is another paragraph</p>",
    };
    var result = MyIteratorBlockMethod(array1).ToArray();
}
0
1

I'd perhaps use a List<string> with a StringBuilder like this:

string[] array1 = {
    "<p>here is a big sentence</p>",
    "file1",
    "file2",
    "<p>this is a big paragraph</p>",
    "file3",
    "file4",
    "file5",
    "<p>this is another paragraph</p>",
};

var result = new List<string>(array1.Length);
var builder = new StringBuilder();

foreach (var row in array1)
{
    if (row.StartsWith("<p>", StringComparison.Ordinal) && row.EndsWith("</p>", StringComparison.Ordinal))
    {
        // if we already have data collected, we should add this before
        // adding the next <p></p> row
        if (builder.Length > 0)
        {
            result.Add(builder.ToString());
            builder.Clear();
        }

        // add the <p></p> row
        result.Add(row);
        // proceed to the next item in array1
        continue;
    }

    // Add commas as necessary
    if (builder.Length > 0)
    {
        builder.Append(',');
    }
    // add the row data
    builder.Append(row);
}

// We could end up here with in situations where the last item isn't <p></p>, so we'll add the last item if necessary
if (builder.Length > 0)
{
    result.Add(builder.ToString());
}
1
string[] array1 = {
    "<p>here is a big sentence</p>",
    "file1",
    "file2",
    "<p>this is a big paragraph</p>",
    "file3",
    "file4",
    "file5",
    "<p>this is another paragraph</p>",
};

List<string> result = new List<string>();

// Temporary list to hold the files between <p> tags
List<string> tempFiles = new List<string>();

foreach (var item in array1)
{
    if (item.StartsWith("<p>"))
    {
        // If there are files in tempFiles, concatenate them and add to result
        if (tempFiles.Any())
        {
            result.Add(string.Join(",", tempFiles));
            tempFiles.Clear(); // Clear the tempFiles list for next batch
        }
        // Add the <p> tag item to the result
        result.Add(item);
    }
    else
    {
        // Collect files between <p> tags
        tempFiles.Add(item);
    }
}

// If there are any remaining files in tempFiles, add them to result
if (tempFiles.Any())
{
    result.Add(string.Join(",", tempFiles));
}

// Convert result list to array
string[] array2 = result.ToArray();

foreach (var str in array2)
{
    Console.WriteLine(str);
}
1
  • 1
    Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
    – Community Bot
    Commented Aug 8, 2024 at 13:06

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.