我试图弄清楚哪种数据结构对表示我的数据有意义。我正在使用一种C#工具,它将更新一组特定类别的名称,SubCategories和SubSubCategories。这是一些示例数据:
OldCategory | OldSubCategory | OldSubSubCategory | NewCategory | NewSubCategory | NewSubSubCategory
-------------------------------------------------------------------------------------------------------------
Hardware | Display | Broken | HD-Hardware | Display |
Hardware | Display | Request upgrade | Requests | Hardware | Display
Software | Excel | Error message | HD-Software | Excel | General Error
Software | Excel | How Do I | HD-Software | Excel | Training
Software | Excel | Plug-in | HD-SoftwareExtensions | Excel |
如您所见,我不能简单地将每个OldCategory
更新为相应的NewCategory
。建立数据是为了使Category
,SubCategory
和SubSubCategory
的每个组合都是唯一的值。例如,Hardware | Display | Request upgrade
将映射到Requests | Hardware | Display
。
如何将三个旧值的组合映射到三个新值的组合?
我当时正在考虑使用Dictionary<Tuple<string, string, string>, Tuple<string, string, string>>
结构,但这似乎太冗长,并且可能使其他开发人员或我未来的自己感到困惑。有什么建议可以更清楚地表示我的数据吗?
答案 0 :(得分:1)
我建议您采用与您推测的路线相同的方式
function getAllKeys<T>(obj: T): (keyof T)[] {
return Object.keys(obj) as (keyof T)[];
}
function exclude<T, K extends readonly (keyof T)[]>(obj: T, excludes: K) {
return getAllKeys(obj)
.filter((key: keyof T): key is Exclude<keyof T, K[number]> =>
!excludes.includes(key));
}
const a = {
foo: 'abc',
bar: 'abc',
baz: 'abc',
yay: true
};
const toExclude = ["foo", "bar"] as const;
const b = exclude(a, toExclude)
.map(key => { // (EXPECTED :: key: 'baz') (ACTUAL :: key: 'foo' | 'bar' | 'baz')
if (key === 'bar') { } // Error
if (key === 'foo') { } // Error
if (key === 'baz') { console.log("Q"); } // Okay
if (key === 'yay') {console.log("F"); } // Okay
});
使用新的Dictionary<Tuple<string, string, string>, Tuple<string, string, string>>
,您可以使用更简洁的语法来实现
ValueTuple
您还可以为元组字段使用名称,如下所示:
var tbl = new Dictionary<(string, string, string), (string, string, string)>();
var newVal = tbl[("Hardware", "Display", "Request upgrade")];
如果您需要更多的灵活性,控件或功能,可以使用下面的类
var tbl = new Dictionary<(string Cat, string SubCat, string SubSubCat), (string Cat, string SubCat, string SubSubCat)>();
如果出于某种原因,您不能继承class CatInfo : Tuple<string, string, string> {
public string Category => Item1;
public string SubCategory => Item2;
public string SubSubCategory => Item3;
public CatInfo(string cat, string subCat, string subSubCat) : base(cat, subCat, subSubCat) { }
}
的子类,或者希望获得更好的性能,则可以仅创建如下所示的不可变结构
Tuple
答案 1 :(得分:1)
这是我在评论中一直在谈论的一个例子:
public class Category : IEquatable<Category>
{
public string MainCategory { get; set; }
public string SubCategory { get; set; }
public string SubSubCategory { get; set; }
private string GetCharacterizer()
{
return $"{MainCategory}#{SubCategory}#{SubSubCategory}";
}
public override int GetHashCode()
{
return GetCharacterizer().GetHashCode();
}
public bool Equals(Category other)
{
if (other == null)
{
return false;
}
return GetCharacterizer().Equals(other.GetCharacterizer());
}
public override bool Equals(object other)
{
if (!(other is Category catOther))
{
return false;
}
return Equals(catOther);
}
}
然后您将创建一个Dictionary<Category, Category>
答案 2 :(得分:0)
创建课程对我来说似乎是最好的选择。这样,您可以创建构造函数并拥有方法。 例如
unsafe
然后您可以将它们放在字典中:
public CategoryClass{
string category;
string subCategory;
string subSubCategory;
}
...或其他对象。