修改字典集合

时间:2015-10-14 19:28:31

标签: c# .net dictionary collections

我目前有一个字典(字符串,整数),它将包含如下所示的值

/ReturnState[1]/ReturnDataState[1]/Form6[1]/Body[1]/Member[1]/FormA1[1] , 91
/ReturnState[1]/ReturnDataState[1]/Form6[1]/Body[1]/Member[1]/FormA1[2] , 92 
/ReturnState[1]/ReturnDataState[1]/Form6[1]/Body[1]/Member[2]/FormA1[1] , 93

此集合是使用简单方法CreatePathCollection(string path,int entityKey)创建的

然而,我面临的挑战如下。

假设我在方法中收到一个键和值,其值为

/ReturnState[1]/ReturnDataState[1]/Form6[1]/Body[1]/Member[1]/FormA1[1] , 94

我想从

更新集合中的以下键
/ReturnState[1]/ReturnDataState[1]/Form6[1]/Body[1]/Member[1]/FormA1[1] , 91 
/ReturnState[1]/ReturnDataState[1]/Form6[1]/Body[1]/Member[1]/FormA1[2] , 92 

 TO 

/ReturnState[1]/ReturnDataState[1]/Form6[1]/Body[1]/Member[1]/FormA1[2] , 91 
/ReturnState[1]/ReturnDataState[1]/Form6[1]/Body[1]/Member[1]/FormA1[3] , 92 

然后添加

/ReturnState[1]/ReturnDataState[1]/Form6[1]/Body[1]/Member[1]/FormA1[1] , 94

所以最后的收藏将是

/ReturnState[1]/ReturnDataState[1]/Form6[1]/Body[1]/Member[1]/FormA1[1] , 94
/ReturnState[1]/ReturnDataState[1]/Form6[1]/Body[1]/Member[1]/FormA1[2] , 91 
/ReturnState[1]/ReturnDataState[1]/Form6[1]/Body[1]/Member[1]/FormA1[3] , 92 
/ReturnState[1]/ReturnDataState[1]/Form6[1]/Body[1]/Member[2]/FormA1[1] , 93

有没有一种优雅的方法来实现这个目标?

3 个答案:

答案 0 :(得分:2)

创建一个模型来表示您的密钥:

以下类表示路径的一部分,如/ReturnState[1],它包含一个解析字符串数据的方法(构造函数)和另一个将数据转换为字符串格式的方法。

public class Part
{
    public string Name { get; set; }
    public int Index { get; set; }

    public Part(string str)
    {
        int location_of_bracket_start = str.LastIndexOf("[");

        if(location_of_bracket_start == -1)
            throw new Exception("Unexpected format");

        Name = str.Substring(0, location_of_bracket_start);

        string rest = str.Substring(location_of_bracket_start);

        Index = int.Parse(rest.Substring(1, rest.Length - 2));

    }

    public string ConvertToStringFormat()
    {
        return string.Format("/{0}[{1}]", Name, Index);
    }
}

以下类表示完整路径(例如/ReturnState[1]/ReturnDataState[1]/Form6[1]/Body[1]/Member[1]/FormA1[1])作为部件列表。它还包含从字符串构造对象并转换为字符串的方法。

public class NodePath : List<Part>
{
    public NodePath(string path)
    {
        string[] parts = path.Split(new []{"/"}, StringSplitOptions.RemoveEmptyEntries);

        foreach (string part in parts)
        {
            this.Add(new Part(part));
        }

    }

    public string ConvertToStringFormat()
    {
        return string.Join("", this.Select(x => x.ConvertToStringFormat()));
    }
}

以下类包含您需要的逻辑:

public class PathClass
{
    private readonly Dictionary<string, int> m_Dictionary;

    public PathClass()
    {
        m_Dictionary = new Dictionary<string, int>();
    }

    public Dictionary<string, int> Dictionary
    {
        get { return m_Dictionary; }
    }

    public void Add(string path, int number)
    {

        if (m_Dictionary.ContainsKey(path))
            MoveOne(path);

        m_Dictionary.Add(path, number);
    }

    public void MoveOne(string path)
    {
        int number = m_Dictionary[path];

        m_Dictionary.Remove(path);

        var moved_node_path = IncrementPath(path);

        if (m_Dictionary.ContainsKey(moved_node_path))
            MoveOne(moved_node_path);

        m_Dictionary.Add(moved_node_path, number);
    }

    private string IncrementPath(string path)
    {
        NodePath node_path = new NodePath(path);

        node_path.Last().Index++;

        return node_path.ConvertToStringFormat();
    }
}

当消费者尝试添加路径时,它会检查它是否存在,如果存在,则会移动现有路径(增加最后一个路径Part的索引)。如果字典还包含我们试图移动的项目,它会以递归方式执行此操作。

我测试了这个:

PathClass path_class = new PathClass();

path_class.Add("/ReturnState[1]/ReturnDataState[1]/Form6[1]/Body[1]/Member[1]/FormA1[1]" , 1);

path_class.Add("/ReturnState[1]/ReturnDataState[1]/Form6[1]/Body[1]/Member[1]/FormA1[1]", 2);

path_class.Add("/ReturnState[1]/ReturnDataState[1]/Form6[1]/Body[1]/Member[2]/FormA1[1]", 3);

path_class.Add("/ReturnState[1]/ReturnDataState[1]/Form6[1]/Body[1]/Member[2]/FormA1[2]", 4);

path_class.Add("/ReturnState[1]/ReturnDataState[1]/Form6[1]/Body[1]/Member[2]/FormA1[1]", 5);

我得到了以下结果:

/ReturnState[1]/ReturnDataState[1]/Form6[1]/Body[1]/Member[1]/FormA1[2], 1
/ReturnState[1]/ReturnDataState[1]/Form6[1]/Body[1]/Member[1]/FormA1[1], 2
/ReturnState[1]/ReturnDataState[1]/Form6[1]/Body[1]/Member[2]/FormA1[2], 3
/ReturnState[1]/ReturnDataState[1]/Form6[1]/Body[1]/Member[2]/FormA1[3], 4
/ReturnState[1]/ReturnDataState[1]/Form6[1]/Body[1]/Member[2]/FormA1[1], 5

请注意,另一种方法是使用Dictionary<NodePath,int>,这意味着您需要为Equals实施GetHashCodeNodePath

<强>更新

如果您不关心模型,可以使用此替换IncrementPath方法(并删除模型),以提高性能:

private string IncrementPath(string path)
{
    int location_of_bracket_start = path.LastIndexOf("[");

    if (location_of_bracket_start == -1)
        throw new Exception("Unexpected format");

    string before_bracket = path.Substring(0, location_of_bracket_start);

    string rest = path.Substring(location_of_bracket_start);

    int index = int.Parse(rest.Substring(1, rest.Length - 2));

    index ++;

    return string.Format("{0}[{1}]", before_bracket, index);
}

答案 1 :(得分:1)

这是我最终的结果 - 不是很优雅,但应该做的工作

static void UpdatePathCollection(Dictionary<string, int> target, string path, int entityKey)
{
    int start, index;
    if (path == null || path.Length < 3 || path[path.Length - 1] != ']'
        || (start = path.LastIndexOf('[', path.Length - 2)) < 0
        || !int.TryParse(path.Substring(start + 1, path.Length - start - 2), out index)
        || index < 0) throw new ArgumentException("path");
    var prefix = path.Substring(0, start + 1);
    var nextKey = path;
    var nextValue = entityKey;
    while (true)
    {
        int oldValue;
        if (!target.TryGetValue(nextKey, out oldValue))
        {
            target.Add(nextKey, nextValue);
            break;
        }
        target[nextKey] = nextValue;
        index++;
        nextKey = prefix + index + "]";
        nextValue = oldValue;
    }
}

答案 2 :(得分:0)

据我所知,用于定义路径的字符串将按字母顺序排列(取决于每个索引是否有超过9个元素)。在这种情况下,您可以使用SortedDictionary并按以下步骤操作:

private readonly SortedDictionary<string, int> sortedDictionary = CreatePathCollection(path, entityKey); 

public void Set(string path, int index)
{
    sortedDictionary.Remove(path);
    var i = 91;
    foreach (var key in sortedDictionary.Keys)
        sortedDictionary[key] = i++;
    sortedDictionary[path] = index;
}

不幸的是,我可能无法详细了解您的问题,但我希望这会给您一些想法。