1

I saw examples, and have implemented linq to convert a delimited string to a 2D array like so:

using System;
using System.Linq;

namespace AACOBusinessModel.Extensions
{
  [Serializable]
  public class TwoDimensionalStringArray
  {
    public TwoDimensionalStringArray(string data)
    {
      // 1;2;3^^4;5;6
      this.Data = (
          from string line
          in data.Split(new string[] { "^^" }, StringSplitOptions.RemoveEmptyEntries)
          select line.Split(';')
        ).ToArray();
    }

    public TwoDimensionalStringArray() { }

    public readonly string[][] Data = { };

    public override string ToString()
    {
      return string.Join("^^",
        from string[] line
        in Data
        select string.Join(";", line)
      );
    }
  }
}

When I tried to make this work in 3D I ran into an issue:

using System;
using System.Linq;

namespace AACOBusinessModel.Extensions
{
  [Serializable]
  public class ThreeDimensionalStringArray
  {
    public ThreeDimensionalStringArray(string data)
    {
      // 1;2;3^^4;5;6@4;4;4^^7;7;7
      this.Data = (
          from string line2D
          in data.Split(new string[] { "@" }, StringSplitOptions.RemoveEmptyEntries)
          from string line
          in line2D.Split(new string[] { "^^" }, StringSplitOptions.RemoveEmptyEntries)
          select line.Split(';')
        );
    }

    public ThreeDimensionalStringArray() { }

    public readonly string[][][] Data = { };

    public override string ToString()
    {
      return string.Join("@",
        from string[][] line2D
        in Data
        select string.Join("^^", 
          from string[] line 
          in line2D
          select string.Join(";", line)
        )
      );
    }
  }
}

I understand that with 2D the ending select was a collection of splits converted to an array thus making a 2D array.

But with 3D, the ending select needs to select a collection of 2D arrays. I don't know how to do this.

UPDATE

I came up with this but I'd like the query syntax if it's possible.

public ThreeDimensionalStringArray(string data)
{
  this.Data = (
      from string line2D
      in data.Split(new string[] { "@" }, StringSplitOptions.RemoveEmptyEntries)
      select (
        from string line
        in line2D.Split(new string[] { "^^" }, StringSplitOptions.RemoveEmptyEntries)
        select line.Split(';')
      ).ToArray()
    ).ToArray();
}

3 Answers 3

2

Not sure how this should be done in query syntax, but here is the method syntax version:

this.Data = data
    .Split(new[] { "@" }, StringSplitOptions.RemoveEmptyEntries)
    .Select(table => table.Split(new[] { "^^" }, StringSplitOptions.RemoveEmptyEntries)
        .Select(row => row.Split(';'))
        .ToArray())
    .ToArray();

In query synax :

this.Data = (
    from table in data.Split(new[] { "@" }, StringSplitOptions.RemoveEmptyEntries)
    select
    (
        from row in table.Split(new[] { "^^" }, StringSplitOptions.RemoveEmptyEntries)
        select row.Split(';')
    ).ToArray()
).ToArray();
Sign up to request clarification or add additional context in comments.

1 Comment

you are a b;a;d^^a;s;s@t;h;a;n;k^^y;o;u
1

You'll need a nested select clause to return a nested collection.

Making a list and then converting to an array will work for you

this.Data = (
    from string line2D
    in data.Split(new string[] { "@" }, StringSplitOptions.RemoveEmptyEntries)
    select new List<string>(    
      from string line
      in line2D.Split(new string[] { "^^" }, StringSplitOptions.RemoveEmptyEntries)
      select line.Split(';')).ToArray());

2 Comments

you got rid of the second .ToArray() call. Nice.
still not compiling on inner from. "cannot convert from 'System.Collections.Generic.IEnumerable<string[]>' to 'int'"
1

I usually end up with mostly the same common general extensions in .NET projects:

public static string[] splitR(this string str, params string[] separators) {
    return str.Split(separators, StringSplitOptions.RemoveEmptyEntries); }

public static O[] convert<I, O>(this I[] array, Converter<I, O> converter) {
    return Array.ConvertAll(array, converter); }

public static string joinT<T>(this T[] values, string separator) {
    return string.Join(separator, values); }

and then just:

string s = "1;2;3^^4;5;6@4;4;4^^7;7;7";

string[][][] s3 = s.splitR("@").convert(x => x.splitR("^^").convert(y => y.splitR(";")));

string s0 = s3.convert(x => x.convert(y => y.joinT(";")).joinT("^^")).joinT("@");

2 Comments

Do you teach at the academy on Vulcan? This is out of this world. I'm going to have to study this over coffee. It's like a spaceship just landed in my back yard. It almost looks like you could take this and make a NDimensionalStringArray class that takes the dimension in the constructor.
it's my bad habit of trying to fit code in as few lines as possible so that I can see more code with less scrolling :] I was thinking of some kind of generic recursive function to handle variable number of delimiters, but got distracted and gave up after few minutes. I just hope that none of your values contain any of those 3 delimiters, because that would be a bit of trouble.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.