比较两本字典了解各自的“加”字;操作和每个“移除”;操作
本文关键字:操作 移除 两本 字典 了解 比较 | 更新日期: 2023-09-27 18:08:25
我有两个类似结构的字典
Dictionary<string, List<int>> Origins
和
Dictionary<string, List<int>> Changes
我在开头创建了Origins。它是初始状态的副本。示例:
Origins["toto"] = new List<int>(){1,2,3};
Origins["tata"] = new List<int>();
Origins["titi"] = new List<int>(){1,2};
在用户操作之后,我将更改保存在changes字典中。基本上,用户可以添加或删除一些链接到字符串的数字。所以我保留了所有更改的踪迹,像这样:
示例:如果用户在"tata"中添加1在字典中,change a have"tata" have 1
如果用户在"toto"中添加4在字典中,change a have"toto"有1,2,3,4
如果用户删除"titi"中的1在字典中,change a have"titi" have 2
我需要Changes字典来知道用户何时返回到原始状态,并进行简单的比较。
如果没有对字符串做任何更改,则Changes字典中没有该字符串的任何条目。
多次更改后,用户可以保存更改。所以现在我需要找到所有的添加和删除操作。
我的第一个想法是比较两个字典,看看操作添加和操作删除。但是怎么做呢?如果我比较相同字符串的列表,我可能知道差异,但我被困在这里。也许有更好的方法?有什么建议吗?
有以下几种情况:
- 一个新的字符串键被添加到
Changes
,以及一些相关的值。 - 更改现有字符串键的值(添加或删除值)。
在情况(1)中,您将在Changes
中拥有Origins
中不存在的条目。在第(2)种情况下,您将在两者中都有一个条目,但具有不同的值列表。
(我要假设的值是一个数学集合,也就是说,一个特定的值只能出现一次,并且排序不重要。如果情况并非如此,那么您就必须稍微修改一下方法。
要检测大小写(1),您可以找到唯一的键:
IEnumerable<string> newKeys = Changes.Keys.Except(Origins.Keys);
显然,Changes
中的每个值都需要"添加"一个新键。您可以简单地迭代newKeys
枚举对象并从Changes
检索值:
foreach (string key in newKeys)
{
IEnumerable<int> addedValues = Changes[key];
// your processing here
}
要检测大小写(2),您需要迭代字典并将Changes中的值集与Origins进行比较。为此,我们将迭代Origins
以获取键和原始值,然后使用Changes
中的键检索项目。(我们将这样做,因为如果我们迭代Changes
,我们可能最终会得到Origins
中不存在的新添加的键,这是我们必须处理的另一种情况。)
foreach (KeyValuePair<string, List<int>> entry in Origins)
{
List<int> originsValues = entry.Value;
List<int> changesValues;
// handle no key in Changes (as pointed out by Guillaume V).
if (!Changes.TryGet(entry.Key, out changesValues)) changesValues = originsValues;
IEnumerable<int> removedValues = originsValues.Except(changesValues);
IEnumerable<int> addedValues = changesValues.Except(originsValues);
// your processing here
}
你可以试试:
Dictionary<string, List<int>> Origin = new Dictionary<string, List<int>>();
Origin["toto"] = new List<int>(){1,2,3};
Origin["tata"] = new List<int>();
Origin["titi"] = new List<int>(){1,2};
Dictionary<string, List<int>> Changes = new Dictionary<string,List<int>>();
Changes["toto"] = new List<int>() { 1, 2, 3, 4 };
Changes["tata"] = new List<int>(){1};
Changes["titi"] = new List<int>() { 2 };
Dictionary<string, List<int>> ToRemove = new Dictionary<string, List<int>>();
Dictionary<string, List<int>> ToAdd = new Dictionary<string, List<int>>();
foreach (string key in Origin.Keys)
{
ToRemove[key] = Origin[key];
ToAdd[key] = Changes[key];
foreach (int i in ToRemove[key])
{
if (ToAdd[key].Contains(i)) //There is no change
{
ToAdd[key].Remove(i);
ToRemove[key].Remove(i);
}
}
}
如果你需要做的就是确定两个对象是否相等,我建议创建你自己的类,并覆盖Equals()
和GetHashInfo()
:
public class ComparableDictionary : Dictionary<string, List<int>>
{
private const int CouldBeAnyConstant = 392;
public override bool Equals(object other)
{
return Equals((ComparableDictionary)other);
}
public bool Equals(ComparableDictionary other)
{
return other != null && (GetHashCode() == other.GetHashCode());
}
public override int GetHashCode()
{
int result = CouldBeAnyConstant;
unchecked
{
foreach (var list in Values)
foreach (var value in list)
result = result*value.GetHashCode();
foreach (var value in Keys)
result = result * value.GetHashCode();
}
return result;
}
}
那么你所要做的就是:
public bool UserHasMadeChanges(ComparableDictionary Origins, ComparableDictionary Changes)
{
return !Origins.Equals(Changes)
}
受Paul Ruane和matmot的启发,我发展了自己的方式:
foreach (var change in this.Changes)
{
List<int> origin = this.Origins[change.Key];
List<int> newValue = change.Value;
//find the basic add and remove
IEnumerable<int> remove = origin.Except(newValue);
IEnumerable<int> add = newValue.Except(origin);
if (!add.Any() && remove.Any())
{
//remove all in the remove list
continue;
}
else if (add.Any() && !remove.Any())
{
//add all in the add list
continue;
}
//if in the same change there are add and remove
IEnumerable<int> dif1 = add.Except(remove);
IEnumerable<int> dif2 = remove.Except(add);
if (dif1.Any())
{
//add all in the dif1 list
}
if (dif2.Any())
{
//remove all in dif2 list
}
}
你觉得这个怎么样