1

If I have a sequence IEnumerable<T> (not numbers, just T):

[ a, b, c, d ]

How to return sort of Pascal's or Floyd's triangle:

a
ab
abc
abcd

so it would be IEnumerable<IEnumerable<T>>?

Wondering whether there a way to achieve this elegantly using LINQ rather than implement manually using loops.

abatishchev
  • 98,240
  • 88
  • 296
  • 433

3 Answers3

2

Here's a method:

T[][] ToTriangle<T>(IEnumerable<T> input)
{
    var inputAsList = input as List<T> ?? input.ToList();
    return inputAsList.Select((t, i) => inputAsList.Take(i + 1).ToArray()).ToArray();
}

From a console app:

static void Main(string[] args)
{
    var input = "Hello, world!";
    var output = ToTriangle(input);
    foreach (var set in output)
    {
        Console.WriteLine(string.Join("",set));
    }
    Console.ReadLine();
}

(A string is an array of characters.)

H
He
Hel
Hell
Hello
Hello,
Hello,
Hello, w
Hello, wo
Hello, wor
Hello, worl
Hello, world
Hello, world!

Scott Hannen
  • 27,588
  • 3
  • 45
  • 62
  • Hope you won't mind to give Etienne some extra points, since his/her solution was posted slightly earlier than yours spite being less effective initially. – abatishchev May 09 '17 at 02:41
1

Using Enumerable.Range in place of for loop lets you build a triangle with a single line of code:

var data = new string[] {"a", "b", "c", "d"};
var triangle = Enumerable.Range(1, data.Length).Select(row => data.Take(row));

Enumerable.Range serves as the outer loop; data.Take(row) serves as the inner loop.

Demo.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Asking proper question is half way to the solution :) I got same but to avoid double sequence enumeration had to require `IReadOnlyCollection` to know its length in advance. Wondering whether there is a way to accept `IEnumerable` but still enumerate it just once. – abatishchev May 09 '17 at 02:01
  • Assuming an arbitrary sequence with Length = 4, I do not think it is a valid Pascal's or Floyd's triangle. – Dustin Kingen May 09 '17 at 02:01
  • @Romoku: I'm not looking for valid Pascal's or Floyd's triangle, just didn't find a better way to explain what I'm looking for. Basically just a triangle. – abatishchev May 09 '17 at 02:02
  • 1
    @abatishchev Since you need to repeat the first entry `n` times, the second entry `n-1` times, the third entry `n-2` times, etc., there is no way to avoid repetition without "materializing" the sequence into an array or a loop. – Sergey Kalinichenko May 09 '17 at 02:03
1

This should work:

var seq = new List<string> { "a", "b", "c", "d" };
var pascal = seq.Select(a => seq.Take(seq.IndexOf(a) +1 ).ToList());

edit:

var seq = new List<string> { "a", "b", "c", "d" };
var pascal = seq.Select((a,i) => seq.Take(i+1).ToList());
Etienne
  • 1,058
  • 11
  • 22