将点标记的命名空间字符串列表排序为嵌套的JSON字符串c#

时间:2018-04-05 00:02:41

标签: c# json

如何将点标记命名空间字符串列表排序为嵌套JSON字符串?

像这样的东西。

var string1 = "example.string.1";
var string2 = "example.string.2";
var string3 = "example.anotherstring.1";

分类到此。

{
    "example": {
        "string": ["1", "2"],
        "anotherstring": ["1"]
    }
}

编辑1

谢谢你们!我能够使用你的答案让它关闭。

这个列表有效:

var strings = new List<string>
{
    "example.string.1",
    "example.string.2",
    "example.anotherstring.1",
};

public void Example()
{
    var dict = new Dictionary<string, dynamic>();
    foreach (var s in strings)
    {
        AddPartsToDictionary(dict, s.Split('.'));
    }
}

public void AddPartsToDictionary(IDictionary<string, dynamic> dict, string[] parts)
{
    for (var i = 0; i < parts.Length; i++)
    {
        if (i < parts.Length - 2)
        {
            if (!dict.ContainsKey(parts[i]))
                dict.Add(parts[i], new Dictionary<string, dynamic>());
            dict = dict[parts[i]];
        }
        else if (i < parts.Length - 1)
        {
            if (!dict.ContainsKey(parts[i]))
            {
                var list = new List<string>();
                dict[parts[i]] = list;
            }
        }
        else
        {
            var list = dict[parts[i - 1]] as List<string>;
            list.Add(parts[i]);
        }
    }
}

结果json

{
    "example":  {
        "string":  [
            "1",
            "2"    
    ],
        "anotherstring":  [
            "1"    
    ]  
  }
}

使用此列表失败

var strings = new List<string>
{
    "example.string.1",
    "example.string.example.1",
    "example.string.2",
    "example.anotherstring.1",
    "example.string.example.2",
    "string.example.2"
};

我可能要对列表或其他内容进行排序,仍在继续处理。希望这有助于搞清楚。

2 个答案:

答案 0 :(得分:2)

一直向下的物体

如果一直使用对象(而不是数组),那么这将是有效的。

var strings = new List<string> {
    "example.string.1",
    "example.string.2",
    "example.anotherstring.1",
};

var result = strings.Aggregate(new Dictionary<string, Object>(), (acc, s) =>
{
    var level = acc;
    foreach(var segment in s.Split('.'))
    {
        if (!level.ContainsKey(segment))
        {
            var child = new Dictionary<string, Object>();
            level.Add(segment, child);
        }

        level = level[segment] as Dictionary<string, Object>;
    }

    return acc;
});

var json = JsonConvert.SerializeObject(result, Formatting.Indented);

输出的对象一直向下。

{
  "example": {
    "string": {
      "1": {},
      "2": {}
    },
    "anotherstring": {
      "1": {}
    }
  }
}

最后一级的数组(with a Fiddle

如果你想在最后一级使用数组,那么我们需要精确定义最后一级的定义。例如,最后一级是否只包含整数?如果是这样,以下工作。

var result = strings.Aggregate(new Dictionary<string, Object>(), (acc, s) =>
{
    Dictionary<string, Object> previousLevel = null;
    Dictionary<string, Object> nextLevel = acc;
    string previousSegment = null;
    foreach (string nextSegment in s.Split('.'))
    {
        if (Int16.TryParse(nextSegment, out _))
        {
            if (previousLevel[previousSegment] is Dictionary<string, Object>)
            {
                previousLevel[previousSegment] = new List<string>();
            }

            var list = previousLevel[previousSegment] as List<string>;
            list.Add(nextSegment);
        }
        else
        {
            if (!nextLevel.ContainsKey(nextSegment))
            {
                var child = new Dictionary<string, Object>();
                nextLevel.Add(nextSegment, child);
            }

            previousSegment = nextSegment;
            previousLevel = nextLevel;

            nextLevel = nextLevel[nextSegment] as Dictionary<string, Object>;
        }
    }

    return acc;
});

输出在最后一级有数组。

{
  "example": {
    "string": [
      "1",
      "2"
    ],
    "anotherstring": [
      "1",
      "2"
    ]
  }
}

此阵列版本仅在最后一个级别仅为integer类型时才有效,这是您原始问题所需的。

更困难的情况是在同一级别处理混合stringinteger类型,其输入看起来像这样:

"System.1", 
"System.2", 
"System.Collections.1", 
"System.Collections.2", 
"System.Collections.Generic.1"

这需要更复杂的算法。如果这是隐藏的要求,请考虑提出一个全新的后续问题,并在对此答案的评论中链接到该问题。

答案 1 :(得分:1)

我认为id快速去了解它,它的关闭但不完全是你想要的。但是我认为它可能会激励你或其他人尝试。

  

免责声明,我不是 Json.net 爱好者,这段代码是   相当不错......不寻常,至少可以说

Demo Here

给出一个列表

var list = new List<string>
   {
      "example.string.1",
      "example.string.2",
      "example.anotherstring.1",
      "example.anotherstring.2",
      "System",
      "System.Diagnostics",
      "System.Text",
      "System.Collections.Generic",
      "System.Linq",
      "System.Diagnostics.1",
      "System.Text.1",
      "System.Collections.Generic.1",
      "System.Linq.1",
      "System.Diagnostics.2",
      "System.Text.2",
      "System.Collections.Generic.2",
      "System.Linq.2"
   };

某些课程

public class RawValue
{
   public RawValue(string key, IEnumerable<IEnumerable<string>> values)
   {
      Key = key;
      Values = values;
   }
   public string Key { get; set; }
   public IEnumerable<IEnumerable<string>> Values { get; set; }
}

public class NameSpace : Dictionary<string, NameSpace>
{
}

一些助手

private static IEnumerable<RawValue> GetRawValues(RawValue value)
{
   return value.Values.Where(x => x.Any())
               .GroupBy(x => x.FirstOrDefault())
               .Select(x => new RawValue(x.Key, x.Select(y => y.Skip(1))));
}

private static NameSpace GroupNameSpaces(IEnumerable<RawValue> groups)
{
   var result = new NameSpace();

   foreach (var group in groups)
      result.Add(group.Key, GroupNameSpaces(GetRawValues(group)));

   return result;

}

主要代码

var groups = list.Select(x => x.Split('.'))
                  .GroupBy(x => x.FirstOrDefault())
                  .Select(x => new RawValue(x.Key, x.Select(y => y.Skip(1))));

var settings = new JsonSerializerSettings
   {
      NullValueHandling = NullValueHandling.Ignore
   };

var result = GroupNameSpaces(groups);

var json = JsonConvert.SerializeObject(result, Formatting.Indented, settings);

Console.WriteLine(json);

<强>输出

{
  "example": {
    "string": {
      "1": {},
      "2": {}
    },
    "anotherstring": {
      "1": {},
      "2": {}
    }
  },
  "System": {
    "Diagnostics": {
      "1": {},
      "2": {}
    },
    "Text": {
      "1": {},
      "2": {}
    },
    "Collections": {
      "Generic": {
        "1": {},
        "2": {}
      }
    },
    "Linq": {
      "1": {},
      "2": {}
    }
  }
}

由于我不知道如何在 Json.Net 中更好地进行序列化,我认为我的失败是必须使用NameSpace : Dictionary<string, NameSpace>。也没有花时间在这上面,我无法弄清楚如何将最后一个节点转换为json数组。虽然我不确定你是否能够考虑它。但是我肯定这可以做得更好