我目前有一个字典(字符串,整数),它将包含如下所示的值
/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
有没有一种优雅的方法来实现这个目标?
答案 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
实施GetHashCode
和NodePath
。
<强>更新强>
如果您不关心模型,可以使用此替换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;
}
不幸的是,我可能无法详细了解您的问题,但我希望这会给您一些想法。