-1

I have an array of string that contains 1000 lines, how to take each 25 lines and group them into one text using linq c#. I can use loops , but I need the code using linq.

3 Answers3

3
var blocks = File.ReadLines(filename)
                    .Select((s, i) => new { s, i })
                    .GroupBy(x => x.i / 25)
                    .Select(g => String.Join(" ", g.Select(x => x.s)))
                    .ToList();

You can also use Morelinq's Batch method: https://code.google.com/p/morelinq/source/browse/MoreLinq/Batch.cs

EZI
  • 15,209
  • 2
  • 27
  • 33
  • @أحمدصوالحة Then replace `File.ReadLines(filename)` with your array. That's all. (Both are `IEnumerable`) – EZI Jul 26 '15 at 16:02
  • I think it cab be useful to explain that grouping is done by the whole part of the division of string index (in enumerable) to 25. First 25 will have 0, next 25 will have 1, etc. – Nikolai Samteladze Jul 26 '15 at 16:12
2

When the question is about a simple linq, I think, the answer should be both good-looking and performant. So, I prepared a test case.

Since this is a community wiki, feel free to update it..

var arr = Enumerable.Range(0, 20000).Select(x => x.ToString()).ToArray();

var t1 = Measure(() =>
{
    var blocks = arr
                .Select((s, i) => new { s, i })
                .GroupBy(x => x.i / 25)
                .Select(g => String.Join(" ", g.Select(x => x.s)))
                .ToList();
}, 1000);


var t2 = Measure(() =>
{
    var allLines = new List<string>();
    for (int i = 0; i < arr.Length; i += 25)
    {
        allLines.Add(String.Join(" ", arr.Skip(i).Take(25)));
    }

}, 1000);


var t3 = Measure(() =>
{
    int count = 0;
    var blocks = arr
                .GroupBy(x => count++ / 25)
                .Select(g => String.Join(" ", g))
                .ToList();
}, 1000);


var t4 = Measure(() =>
{
    var blocks = arr.Batch(25, x => x)
                .Select(g => String.Join(" ", g))
                .ToList();
}, 1000);


Console.WriteLine("EZI: {0}\nShar1er80: {1}\nModified-EZI: {2}\nMoreLinq'sBatch: {3}", t1,t2,t3,t4);

long Measure(Action action, int n)
{
    action();
    var sw = Stopwatch.StartNew();
    for (int i = 0; i < n; i++)
    {
        action();
    }
    return sw.ElapsedMilliseconds;
}

OUTPUT:

EZI: 3548
Shar1er80: 24362
Modified-EZI: 1782
MoreLinq'sBatch: 1300
L.B
  • 114,136
  • 19
  • 178
  • 224
1

Because you've tagged take in your question, here's how you can get the same results as @EZI using Take() from Linq.

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    public static void Main()
    {
        List<string> _1000Lines = new List<string>();
        for (int i = 1; i <= 1000; i++)
            _1000Lines.Add(i.ToString());

        for (int i = 0; i < _1000Lines.Count; i += 25) 
        {
            // Use Skip() to skip the previous 25 items from the previous iteration
            Console.WriteLine(String.Join(" ", _1000Lines.Skip(i).Take(25)));
        }
    }
}

Fiddle Demo

Shar1er80
  • 9,001
  • 2
  • 20
  • 29