0

Does anyone know of a C# equivalent of this occassional PHP task:

Convert dot syntax like "this.that.other" to multi-dimensional array in PHP

That is, to convert a list of strings like level1.level2.level3 = item into a dictionary or multidimensional array?

I'd assume the dictionary would need to hold items of type object and I'd later cast them to Dictionary<string, string> or a string if it's a final item.

Community
  • 1
  • 1
silkfire
  • 24,585
  • 15
  • 82
  • 105
  • i think this will need a degree of reflection to achieve this. might be helpful to state the use case for this, as there may be alternative solutions to tackle your problem – jim tollan Sep 05 '16 at 12:15
  • Do you just need to parse 1 string as a dictionary, or is there a more complex use case? Just splitting the text can be done fairly easy like so https://dotnetfiddle.net/NEbUK7 – Icepickle Sep 05 '16 at 12:26
  • @Icepickle No, all strings in the list. If the loop encounters an existing key, then it should append that string to the existing sub-dictionary (hope this makes sense?). – silkfire Sep 05 '16 at 12:30
  • 1
    @silkfire If you combine jdwengs answer for pattern matching and mine, I guess you could come to an answer ;) I didn't really take the ` = item` in mind, I though the last item after the `.` would anyhow be the value – Icepickle Sep 05 '16 at 13:01

2 Answers2

0

Does code like this work?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string input = "level1.level2.level3 = item";

            string pattern = "^(?'keys'[^=]+)=(?'value'.*)";

            Match match = Regex.Match(input, pattern);

            string value = match.Groups["value"].Value.Trim();
            string[] keys = match.Groups["keys"].Value.Trim().Split(new char[] {'.'}, StringSplitOptions.RemoveEmptyEntries);

            Dictionary<string, List<string>> dict = new Dictionary<string, List<string>>();

            foreach (string key in keys)
            {
                if (dict.ContainsKey("key"))
                {
                    dict[key].Add(value);
                }
                else
                {
                    dict.Add(key, new List<string>() { value });
                }
            }

        }
    }
}
jdweng
  • 33,250
  • 2
  • 15
  • 20
0

I guess you could do it like this, though (i'm sure more optimization could be done)

using System;
using System.Collections.Generic;

public class Program
{
    public class IndexedTree {
        private readonly IDictionary<string, IndexedTree> _me;
        private object _value;
        private readonly string _splitKey = ".";

        public IndexedTree this[string key] {
            get {
                return _me[key];
            }
        }

        public object Value { get; set; }

        public void Add(string dottedItem) {
            if ( string.IsNullOrWhiteSpace( dottedItem ) ) {
                throw new ArgumentException("dottedItem cannot be empty");
            }
            int index;
            if ( (index = dottedItem.IndexOf( _splitKey ) ) < 0 ) {
                throw new ArgumentException("dottedItem didn't contain " + _splitKey);
            }
            string key = dottedItem.Substring(0, index), rest = dottedItem.Substring(index + 1);
            IndexedTree child;
            if (_me.ContainsKey(key)) {
                child = _me[key];
            } else {
                child = new IndexedTree( _splitKey );
                _me.Add(key, child);
            }
            if (rest.IndexOf(_splitKey) >= 0) {
                child.Add(rest);
            } else {
                // maybe it can be checked if there is already a value set here or not
                // in case there is a warning or error might be more appropriate
                child.Value = rest;
            }
        }

        public IndexedTree(string splitKey) {
            _splitKey = splitKey;
            _me = new Dictionary<string, IndexedTree>();
        }
    }

    public static void Main()
    {
        IndexedTree tree = new IndexedTree(".");
        tree.Add("Level1.Level2.Level3.Item");
        tree.Add("Level1.Level2.Value");
        Console.WriteLine(tree["Level1"]["Level2"].Value);
        Console.WriteLine(tree["Level1"]["Level2"]["Level3"].Value);
    }
}

You could see the result here: https://dotnetfiddle.net/EGagoz

Icepickle
  • 12,689
  • 3
  • 34
  • 48