我应该使用什么数据结构将三个“旧”值映射到三个“新”值?

时间:2019-03-14 17:33:25

标签: c# data-structures mapping

我试图弄清楚哪种数据结构对表示我的数据有意义。我正在使用一种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。建立数据是为了使CategorySubCategorySubSubCategory的每个组合都是唯一的值。例如,Hardware | Display | Request upgrade将映射到Requests | Hardware | Display

如何将三个旧值的组合映射到三个新值的组合?

我当时正在考虑使用Dictionary<Tuple<string, string, string>, Tuple<string, string, string>>结构,但这似乎太冗长,并且可能使其他开发人员或我未来的自己感到困惑。有什么建议可以更清楚地表示我的数据吗?

3 个答案:

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

...或其他对象。