0

I am looking for a way to make a unique list using linq

original list

Level 01
Level 01
-- Blank Line --
Level 02
Level 02
-- Blank Line --
Level 03
Level 03
-- Blank Line --
Level 04
Level 04

and so on

what I want to do:

Level 01
-- Blank Line --
Level 02
-- Blank Line --
Level 03
-- Blank Line --
Level 04

Thanks

maccettura
  • 10,514
  • 3
  • 28
  • 35
AlanC
  • 15
  • 2
  • Please improve the formatting of your question. It's incredibly hard to read in its current format. See https://stackoverflow.com/editing-help – Stanislas Feb 22 '21 at 16:15
  • If you format the lines as code it will not wrap newlines together. – juharr Feb 22 '21 at 16:18
  • Is it possible that you might have, say, a "Level 01" line somewhere AFTER the "Level 02" lines later in the list? Or is it guaranteed that after any given blank line, there will be no repeats of any non-blank lines preceding that blank line? – Matthew Watson Feb 22 '21 at 16:37
  • Also see https://stackoverflow.com/questions/5729572/eliminate-consecutive-duplicates-of-list-elements – Matthew Watson Feb 22 '21 at 16:39
  • Yes, I was unable to format the post, thank you for formatting my post and the link – AlanC Feb 23 '21 at 18:10

2 Answers2

1

You could use Enumerable.Aggregate:

string blankLine = // whatever a blank line is

var list = new List<string>
{
    "Level 01",
    "Level 01",
    blankLine,
    "Level 02"
    "Level 02"
    blankLine,
    // ...
};

var unique = list
    .Aggregate(
        Enumerable.Empty<string>(), // Initial accumulator value
        (acc, x) => x == blankLine || !acc.Contains(x) ? acc.Append(x) : acc); 
Johnathan Barclay
  • 18,599
  • 1
  • 22
  • 35
0

Your specification is not complete. What do you want with this input:

Level 01
Level 02
-- Blank Line --
Level 03
Level 04
-- Blank Line --

And how about two contiguous blank lines?

Level 01
Level 01
-- Blank Line --
-- Blank Line --
Level 02

And what do you want if your input sequence is empty? An empty output, or only a blank line?

Let's assume you don't have this. You requirement is:

Given an input sequence of strings, without two contiguous blank lines. Take the first string, skip all strings until the first empty string. Take the empty string. Repeat this until the end of your sequence.

So you take the first "Level 01", skip all lines until the blank line, you take the blank line, and the first line after that: "Level 02". Skip all lines until the next blank line, take this next blank line, etc.

It might be that "empty string" in fact is "-- Blank Line --". I assume you are smart enough to change the code accordingly.

You can do that in one big LINQ statement. I think your code will be much easier to read, understand, reuse, test, maintain if you make an extension method. If you are not familiar with extension methods, see extension methods demystified

static IEnumerable<string> SkipContiguousLines(this IEnumerable<string> source)
{
    // TODO implement
}

Let's first see if the interface is like you want:

IEnumerable<string> lines = ... // get the input
IEnumerable<string> remainingLines = lines.SkipContiguous();

Or in a bigger LINQ:

var result = orderLines.GroupBy(orderLine => orderLine.OrderId)
                       .Select(group => new
                       {
                           OrderId = group.Key,
                           OrderLines = group.SkipContiguous(),
                       });

The code is fairly straightforward:

static IEnumerable<string> SkipContiguousLines(this IEnumerable<string> lines)
{
    string blankLine = String.Empty;   // or ----- Blank Line ---- ?

    using (var lineIterator in lines.GetEnumerator())
    {
        bool lineAvailable = lineIterator.MoveNext();
        while (lineAvailable)
        {
            // there is still something in your input:
            yield return lineIterator.Current;

            // skip until blank line:
            while (lineAvailable && lineIterator.Current != blankLine)
            {
                 lineAvailable = lineIterator.MoveNext();
            }

            // if not at end, you found a blank line: return the blank line
            if (lineAvailable) yield return blankLine;
        }
    }
}
Harald Coppoolse
  • 28,834
  • 7
  • 67
  • 116
  • You assumed correct, I am smart enough, only I am a beginner so I am still learning. Thanks – AlanC Feb 23 '21 at 18:11