1

I have a string[] like:

{"DNSD90OOP","234","TEST","","32324" "ASERT89UY","567","TEST2","","1256" 
"MSEWQ89UY","507","TEST3","","1206"}

I would expect the result like:

{"DNSD90OOP","234","TEST","","32324"},
{"ASERT89UY","567","TEST2","","1256"},
{"MSEWQ89UY","507","TEST3","","1206"}

How can I do it in C# using LINQ or just C#?

prezequias
  • 267
  • 1
  • 5
  • 17
  • 1
    @BWA the question doesn't ask how to start copying from a specific element. The title asks how to copy every nth element although the desired results show *batching* – Panagiotis Kanavos Jan 11 '22 at 11:13
  • @BWA the question doesn't ask how to copy items at all. – Panagiotis Kanavos Jan 11 '22 at 11:18
  • what are you trying to do? Parse a CSV file? Produce concrete objects? You could use a parsing library (or write your own parser) to do what you want directly, without generating a string array first. Right now a missing element would result in invalid batches. A CSV parser could handle the missing element in a line and parse the next one. – Panagiotis Kanavos Jan 11 '22 at 11:21
  • What are you *actually* trying to do? What is the actual input and actual output? Strings? JSON? CSV files? The input isn't a `string[]` and the output isn't a valid JSON string. – Panagiotis Kanavos Jan 11 '22 at 12:56
  • Does this answer your question? [How to split an array into chunks of specific size?](https://stackoverflow.com/questions/11207526/how-to-split-an-array-into-chunks-of-specific-size) – Hans Kilian Jan 11 '22 at 13:17

1 Answers1

3

Updated: Parsing a CSV file

It looks like the actual question is how to parse a CSV file into records.

A crude approach would be to read the file one line at a time and split that line:

var lines=File.ReadLines(path);
foreach(var line in lines)
{
    var parts=line.Split(",");
}

ReadLines returns an IEnumerable<string> that returns one line at a time instead of reading and splitting the entire file at once.

This code can be converted to a LINQ query, and even be used to construct records:

var records= File.ReadLines(path)
                 .Select(line=>line.Split(","))
                 .Select(b=>new SomeRecord(b[0],b[1],b[2],b[3],b[4]))
                 .ToArray();

This code won't trim the surrounding quotes. To do that, one would have to use Trim('"'), eg b[0].Trim('"'). That's not the most elegant solution.

If the file is retrieved as a single string through an API, a StringReader can be used to read it line by line, eg:

public static IEnumerable<string> ReadStringLines(string input)
{
    using var reader=new StringReader(input);
    while(true)
    {
        var line=reader.ReadLine();
        if(line!=null)
        {
            yield return line;
        }
        else
        {
            break;
        }
    }
}

...

var records= MyUtils.ReadStringLines(input)
                 .Select(line=>line.Split(","))
                 .Select(b=>new SomeRecord(b[0],b[1],b[2],b[3],b[4]))
                 .ToArray();

Another possibility would be to use a regex to both split and trim, but a better solution would be to use a CSV parsing library like CsvHelper, that can handle all the quirks in a CSF file, like quoted fields, newlines in fields and even missing fields

Original answer

The result shows batching the array elements in batches of 5 items, not accessing every nth element. Batching in LINQ is possible using Chunk in .NET (Core) 6 and later. In older versions you can use MoreLINQ's Batch.

In .NET 6, you can use :

var batches=elements.Chunk(5);

batches is an IEnumerable<string[]>. You can convert them to an array with ToArray or you can use Select to construct objects from the batch items, eg :

var records=elements.Chunk(5)
                    .Select(b=>new SomeRecord(b[0],b[1],b[2],b[3],b[4]))
                    .ToArray();

MoreLinq's Batch returns an IEnumerable<IEnumerable<T>>. This avoids allocating a new array for every batch. If you need to handle the items as an array though, you'd need an extra ToArray().

var records=elements.Batch(5)
                    .Select(batch=>{
                        var b=batch.ToArray();
                        return new SomeRecord(b[0],b[1],b[2],b[3],b[4]);
                    })
                    .ToArray();
Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
  • Thanks Panagiotis, the result I get is: {"DNSD90OOP","234","TEST","","32324 ASERT89UY"}, {"567","TEST2","","1256", "MSEWQ89UY 507"}, {"TEST3","","1206"}. The 5th element does not have a comma, and therefore it's joining with the 6th element and so forth. How can I enforce to split the array after every 5th element? Many thanks – prezequias Jan 11 '22 at 11:48
  • 1
    @prezequias What comma? There are no commas in an array. You asked about accessing array items, not parsing a CSV. If what you posted was the actual input file the answer would be different. There's no array yet. The brute force way would be to read the file line by line and only split individual lines. Or use a library like CsvHelper to parse the file directly into records – Panagiotis Kanavos Jan 11 '22 at 12:51
  • Panagiotis, thanks for helping. The point is, I receive the payload on this pattern and I need to split into array every 5th element where is not separated by any comma. You solution brings the arrays but it joins the elements without commas into one as my previous comment. Is there any way to create arrays on every 5th element? Thanks. – prezequias Jan 11 '22 at 12:59