#c# #data-structures #mapping
#c# #структуры данных #сопоставление
Вопрос:
Я пытаюсь выяснить, какая структура данных имела бы смысл для представления моих данных. Я работаю над инструментом C #, который обновит названия определенного набора категорий, подкатегорий и подсубкатегорий. Вот несколько примеров данных:
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>>
структуры, но это кажется ужасно подробным и потенциально сбивающим с толку других разработчиков или меня в будущем. Есть предложения по более четкому представлению моих данных?
Комментарии:
1. Почему бы просто не создать класс и не использовать объекты?
2. Можете ли вы добавить пример преобразования?
3. @Bedir Я мог бы. Как вы думаете, имеет ли это смысл в контексте моего вопроса и по сравнению с
Dictionary<Tuple<string, string, string>, Tuple<string, string, string>>
?4. @stuartd Это для нашей системы оформления заявок в службу поддержки. Я взаимодействую с API, и категории являются свойствами заявки. Итак, билет с тремя «старыми» значениями категории должен быть изменен, чтобы иметь три «новых» значения категории. Я надеюсь, что это имеет смысл.
5. Использование
Dictionary<3-tuple,3-tuple>
просто кажется мне неправильным. Я подозреваю, что использование более детализированной версии ответа @Bedir иDictionary<Category, Category>
было бы проще для понимания, отладки и мониторинга.
Ответ №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>
Комментарии:
1. Потрясающе, спасибо. Это более полный ответ, поэтому я отмечу это как ответ.
2. Не обращайте внимания на мой последний (теперь удаленный) комментарий. Я был идиотом 🙂
3. @LewsTherin: Возможно, вы также захотите реализовать операторы
==
и!=
(вы должны выполнить оба, если вы выполняете одно). Но, поскольку у вас естьEquals
, это просто. Кроме того, напишите несколько тестов, это быстро скомпонованный код
Ответ №2:
Я бы предложил пойти тем же путем, который вы предполагаете, т. Е.
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
или хотите немного повысить производительность, тогда вы можете просто создать неизменяемую структуру, как показано ниже
struct CatInfo {
public string Category { get; }
public string SubCategory { get; }
public string SubSubCatergory { get; }
public CatInfo(string cat, string subCat, string subSubCat) {
Category = cat;
SubCategory = subCat;
SubSubCatergory = subSubCat;
}
public bool Equals(CatInfo other) {
return string.Equals(Category, other.Category) amp;amp; string.Equals(SubCategory, other.SubCategory) amp;amp; string.Equals(SubSubCatergory, other.SubSubCatergory);
}
public override bool Equals(object obj) {
if (obj is null)
return false;
return obj is CatInfo info amp;amp; Equals(info);
}
public override int GetHashCode() {
unchecked {
int hashCode = (Category != null ? Category.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (SubCategory != null ? SubCategory.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (SubSubCatergory != null ? SubSubCatergory.GetHashCode() : 0);
return hashCode;
}
}
public static bool operator ==(CatInfo info1, CatInfo info2) {
return info1.Equals(info2);
}
public static bool operator !=(CatInfo info1, CatInfo info2) {
return !(info1 == info2);
}
}
Ответ №3:
Создание класса кажется мне лучшим вариантом. Таким образом, вы можете создать конструктор и иметь методы. Например.
public CategoryClass{
string category;
string subCategory;
string subSubCategory;
}
А затем вы можете поместить их в словарь:
static void Main(string[] args)
{
CategoryClass oldCategory = new CategoryClass();
CategoryClass newCategory = new CategoryClass();
Dictionary<CategoryClass, CategoryClass> dict = new Dictionary<CategoryClass, CategoryClass>();
}
… или другой объект.
Комментарии:
1. Если вы собираетесь это сделать, вам захочется реализовать GetHashKey в классе (например, путем хэширования некоторой конкатенации строк). Вы захотите использовать это как ключ словаря.
2. Я думаю, что именно так я и собираюсь поступить (обернуть категории в класс, а затем настроить сопоставление с помощью
Dictionary<ClassName, ClassName>
). Это кажется намного более читаемым. Спасибо!3. И не забывайте, GetHashKey и другие требования, чтобы ссылочный тип действовал как значение (я не помню их все, но равно и т.д.)
4. @Flydog57 Можете ли вы привести пример того, как бы вы это сделали? Я могу только найти,
Object.GetHashCode()
и это возвращаетint
.5. blogs.msdn.microsoft.com/ericlippert/2011/02/28 / … для GetHashCode. Самый простой способ сделать это — создать закрытую функцию, которая, например, объединяет три строки с разделителем и использует его для равенства, чтобы получить хэш-код (просто возьмите хэш-код объединенных строк) и т.д. И я нашел то, что искал: learn.microsoft.com/en-us/dotnet/csharp/programming-guide /…