【问题标题】:Modifying a dictionary collection修改字典集合
【发布时间】:2016-01-13 01:14:00
【问题描述】:

我目前有一个字典(字符串,int),它将保存如下值

/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

有没有优雅的方法来完成这个?

【问题讨论】:

  • 你的字典是Dictionary<string,int>吗?在您的示例中,键是整个字符串/ReturnState[1]/ReturnDataState[1]/Form6[1]/Body[1]/Member[1]/FormA1[1],值是94?
  • 是的,你是对的,Yacoub!我将编辑我的问题以增加清晰度。
  • 如何向我们展示“简单方法 CreatePathCollection(string path, int entityKey)”
  • 首先,您需要向我们展示一些代码,看看您到目前为止尝试了什么——这里不是拼图的地方!其次,我试图弄清楚你的“路径”逻辑是什么,即你的所有键是否都按照你在示例中显示的方式进行编码,例如 /sometext[somenumber]/...
  • @user3375390,您要在CreatePathCollection 方法中解决的问题是什么?你能解释一下密钥的语法吗?您正在将某些键/值的接收与其他项目的更新联系起来?这里有什么关系?你应该解决这个问题,让它更容易理解

标签: c# .net dictionary collections


【解决方案1】:

创建一个模型来表示您的密钥,如下所示:

下面的类表示像/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();
    }
}

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

我是这样测试的:

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&lt;NodePath,int&gt;,这意味着您需要为NodePath 实现EqualsGetHashCode

更新:

如果您不关心模型,出于性能原因,可以将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);
}

【讨论】:

    【解决方案2】:

    这是我最终的结果 - 不是很优雅,但应该可以完成这项工作

    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;
        }
    }
    

    【讨论】:

    • 非常感谢 Ivan .. 我想这就是我需要的!
    【解决方案3】:

    据我了解,用于定义路径的字符串将按字母顺序出现(这取决于每个索引是否有超过 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;
    }
    

    很遗憾,我可能无法详细了解您的问题,但我希望这能给您一些想法。

    【讨论】:

    • 感谢您尝试 Ronald,但我认为这行不通。
    • 那么你想要实现什么?我不完全理解您要实现的逻辑
    猜你喜欢
    • 1970-01-01
    • 2011-02-11
    • 1970-01-01
    • 1970-01-01
    • 2022-01-14
    • 1970-01-01
    • 1970-01-01
    • 2013-05-14
    相关资源
    最近更新 更多