I'm trying to determine what data structure I need here. I have a list of fields to update in an spreadsheet. The fields are static and predictable. Example shot below (field names are more meaningful in reality than the examples shown). I may not have all values to enter; i.e. I may only be inserting data into fields "Example Field 1 - 8". I'll then use only the populated values to search for the field name and update that entry in the spreadsheet.
.
My idea was to have a Dictionary<string, string> with the key being the Field Name and instantiate with an empty value field. e.g.
public Dictionary<string, string> FieldList = new Dictionary<string, string>
{
{"Example Field 1", ""},
{"Example Field 2", ""},
{"Example Field 3", ""},
...
};
But this seems a little clunky to me as I will have to know the full field name to add the value to the dictionary later which seems to defeat the purpose; e.g. FieldList["Example Field 2"] = "Field 2 Value";
My other idea was to create a class...
class SpreadsheetField
{
public string DisplayName { get; set; }
public string Value { get; set; }
}
class SpreadsheetFields
{
SpreadsheetField ExampleField1 = new SpreadsheetField
{
DisplayName = "Example Field 1"
};
SpreadsheetField ExampleField2 = new SpreadsheetField
{
DisplayName = "Example Field 2"
};
...
}
This option gives me nice intellisense that I can use to reference the fields. i.e. SpreadsheetField.ExampleField2.Value = "Field 2 Value"
I can then use the DisplayName property to find the field in the location in the spreadsheet I need to update. But is that overkill for what I'm trying to do here? Should I stick to a Dictionary or is there a better option? Also, for this class solution, is there a way I could make DisplayName ReadOnly/Const after it is set as it should not be editable once initialised.
Option A has the advantage of being easier to expand. You don't need to pre-populate the dictionary as, for example FieldList["Example Field 2"] = "Field 2 Value"; will create a new entry if one does not exist.
Option B is slightly faster (no need for a key lookup), and as you say Intellisense helps you. It does need code changes for adding/removing fields.
Your choice.
If you use a dictionary, you could do with add only pairs that do have a value.
Dictionary<string, string> dict = new Dictionary<string, string>();
//----------
string value = "test";
string key = "some key";
if (dict.ContainsKey(key))
{
dict[key] = value;
}
else
{
if(value == string.Empty)
{
dict.Remove(key);
}
else
{
dict.Add(key, value);
}
}
perhaps some "classic" if/else, but it keeps the Dictionary clean and efficient, and its less code than the static written out one
In a class it can be something like:
using System.Collections.Generic;
using System.Linq;
public class SpreadsheetMapper
{
private static readonly Dictionary<string, string> dict = new Dictionary<string, string>();
public static void Map(string key, string value)
{
if(key==String.Empty)
{
throw new ArgumentException();
}
if (dict.ContainsKey(key))
{
dict[key] = value;
}
else
{
if (value == string.Empty)
{
dict.Remove(key);
}
else
{
dict.Add(key, value);
}
}
}
public static string Value(string key)
{
if (dict.ContainsKey(key) & key!=String.Empty)
{
return dict[key];
}
}
public static IEnumerable<string> Keys(string value)
{
return dict.Where(x => x.Value == value).Select(x=> x.Key);
}
}
SpreadsheetMapper.Map("some key 1", "some value")
SpreadsheetMapper.Value("some key")
etc...
You could use null conditional operator with the dictionary values so you don't have to initialize with an empty string, it checks if it's null: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/member-access-operators
Example:
A?.B?.Do(C);
Related
I want to create "list of list of list". It should be:
Group (has a list of Members)
Member (has a Name and list of Properties)
Property (has Name and Value)
What I want is to have a possibility to add Property into Member (specified by its name) inside defined Group. Someting like this:
membersgroup.AddNewMember(memberXYZ);
...
membersgroup.memberXYZ.AddProperty(nameXYZ, valueXYZ).
I have trouble achieving this using list... I found class Hashable, but I am not sure if this is usable... and cannot make it works too...
Thank for any suggestion :)
Well, I suggest you create a custom class instead of your approach. But otherwise you can use a Dictionary.
var properties = new Dictionary<string, string>();
properties.Add("Prop1", "Value");
var members = new Dictionary<string, Dictionary<string, string>>();
members.Add("Member1", properties);
var group = new Dictionary<string, Dictionary<string, Dictionary<string, string>>>();
group.Add("GroupName", members);
public class Group
{
public Group()
{
Members = new List<Member>();
}
public IEnumerable<Member> Members { get; set; }
}
public class Member
{
public Member()
{
Properties = new Dictionary<string, string>();
}
public string Name { get; set; }
IDictionary<string, string> Properties { get; set; }
}
The dictionary can take a key and a value, and the key should be unique.
You can also create a class property if you want to add another thing beside the name and the value
I would use indexers.
Here's a partial implementation:
class Group
{
private List<Member> _members;
public string this
{
get
{
return _members.Find(m => m.Name == value);
}
// You can also implement set here if you want...
}
}
class Member
{
private List<Property> _properties;
public string Name {get;set;}
public string this
{
get
{
return _properties.Find(m => m.Name == value);
}
}
}
class Property
{
public string Name {get;set;}
public string Value {get;set;}
}
And the usage:
var g = new Group();
g[memberName][propertyName].Value = someValue;
Note: This implementation is partial! it still needs constructor logic and any other logic you might need.
Likely the best solution is to use the C# class Dictionary - as suggested by zetawars, or a custom class - as suggested by Zohar Peled, or some mix of the two - as suggested by gandalf.
However, in order to use syntax similar to what is requested in the question...
membersgroup.AddNewMember(memberXYZ);
...
membersgroup.memberXYZ.AddProperty(nameXYZ, valueXYZ).
You can abuse ExpandoObject and Action, and do something awesome like this:
dynamic membersgroup = new ExpandoObject();
var getNewMemberObject = new Func<dynamic>(() =>
{
dynamic memberObject = new ExpandoObject();
var addPropertyAction = new Action<string, string>((propertyName, propertyValue) =>
{
((IDictionary<string, object>)memberObject).Add(propertyName, propertyValue);
});
memberObject.AddProperty = addPropertyAction;
return memberObject;
});
var addNewMemberAction = new Action<string>((memberName) =>
{
((IDictionary<string, object>)membersgroup).Add(memberName, getNewMemberObject());
});
membersgroup.AddNewMember = addNewMemberAction;
string memberXYZ = nameof(memberXYZ);
string nameXYZ = nameof(nameXYZ);
string valueXYZ = nameof(valueXYZ);
// look we did it!
membersgroup.AddNewMember(memberXYZ);
membersgroup.memberXYZ.AddProperty(nameXYZ, valueXYZ);
// and it actually works
var actualValue = membersgroup.memberXYZ.nameXYZ;
Console.WriteLine(actualValue); // "valueXYZ"
(for science of course)
I have multiple dictionaries. Each of them contains the same keys, just with different values. I am using them for translations. They are dynamically created..
So, it looks something like this:
DictionaryEng:
first_page_name = "First page"
second_page_name = "Second page"
DictionaryRu:
first_page_name = "Первая страница"
second_page_name = "Вторая страница"
I would like this informations to be shown in DataGrid or, so user can change the values. It should look like this, end values to be editable.
What's the best practice to do this?
Basically you need to bind the DataGrid to a Collection
<DataGrid
ItemsSource="{Binding Lines}" AutoGenerateColumns="True"
I'll mock up the creation of the dictionary with stub functions called in the ViewModel c.tor
public class MyVM : ViewModelBase
{
public MyVM()
{
Line.DictionaryEng = Line.DictionaryEngStub();
Line.DictionaryRu = Line.DictionaryRuStub();
lines = new ObservableCollection<Line>(Line.DictionaryEng.Keys.Select(k => new Line() { KeyWord = k }));
}
private ObservableCollection<Line> lines;
public ObservableCollection<Line> Lines
{
get { return lines; }
set
{
lines = value;
OnPropertyChanged("Lines");
}
}
}
where the underlying class is defined as follows
public class Line : ViewModelBase
{
internal static Dictionary<string, string> DictionaryEngStub()
{
return new Dictionary<string, string>()
{
{ "first_page_name ","First page" },
{ "second_page_name ","Second page" }
};
}
internal static Dictionary<string, string> DictionaryRuStub()
{
return new Dictionary<string, string>()
{
{"first_page_name ","Первая страница" },
{"second_page_name ","Вторая страница" }
};
}
internal static Dictionary<string, string> DictionaryEng = new Dictionary<string, string>();
internal static Dictionary<string, string> DictionaryRu = new Dictionary<string, string>();
private string keyWord;
public string KeyWord
{
get { return keyWord; }
set
{
keyWord = value;
OnPropertyChanged("keyWord");
}
}
public string EnglishWord {
get
{
string english;
if (DictionaryEng.TryGetValue(keyWord ?? "", out english))
{
return english;
}
return null;
}
}
public string RussianhWord
{
get
{
string russian;
if (DictionaryRu.TryGetValue(keyWord ?? "", out russian))
{
return russian;
}
return null;
}
}
}
Notice that the translations have only a getter to retrieve the string from the dictionary.
You can easily make them editable by adding a setter to save the new translation into a persistence layer. Furthermore, English and Russian dictionaries are generic enough to be renamed as from/to dictionaries. Once the user selects a language in another combobox, you can reset the dictionary accordingly.
Since I have a stub here, the setter does not make much sense, but just to give you and idea...
private string englishSaved;
public string EnglishWord {
get
{
if (englishSaved != null)
{
return englishSaved;
}
string english;
if (DictionaryEng.TryGetValue(keyWord ?? "", out english))
{
return english;
}
return null;
}
set
{
englishSaved = value; //save the new translation into a persistence layer
}
}
I am unsure whether this is possible with an ArrayList or a Dictionary or whether it would be something else, if so I wonder where you could point me in the right direction...
Can you have an ArrayList with Multiple Values i.e.
ArrayList weather = new ArrayList();
weather.Add("Sunny", "img/sunny.jpg");
weather.Add("Rain", "img/Rain.jpg);
To then assign to controls like below.
if (WeatherValue = 0)
{
Label1.Text = weather[0].ToString;
Image1.ImageUrl = weather[0].ToString;
}
Or can I do this with a Dictionary
Dictionary<string, string> dict = new Dictionary<string, string>();
dict.Add("Cloudy", "../img/icons/w0.png"); //[0]
dict.Add("Rain", "../img/icons/w1.png"); //[1]
Label1.Text = dict[0].VALUE1; //So this would get Cloudy
Image.ImageUrl = dict[0].VALUE2; //This would get ../img/w0.png
How do you call the values of a dictionary separately using [0], and [1] ? etc
There's no reason to still use ArrayList, use the System.Collections.Generic.List<T>-class. Then you keep compile time safety and you don't need to cast everything.
In this case you should create a custom class:
public class Weather
{
public double Degree { get; set; }
public string Name { get; set; }
public string IconPath { get; set; }
public override string ToString()
{
return Name;
}
}
Then you can use this readable and maintainable code:
List<Weather> weatherList = new List<Weather>();
weatherList.Add(new Weather { Name = "Sunny", IconPath = "img/sunny.jpg" });
weatherList.Add(new Weather { Name = "Rain", IconPath = "img/Rain.jpg" });
if (WeatherValue == 0) // whatever that is
{
Label1.Text = weatherList[0].Name;
Image1.ImageUrl = weatherList[0].IconPath;
}
Update: according to your edited question. A dictionary doesn't make much sense because you can't access it via index(it has no order) but only via key. Since that would be the weather-name you have to know it beforehand. But it seems that you don't have it.
So either loop all key-value pairs in the dictionary and use the key for the name and the value for the path or simply use a real class which would be much better.
If you don't want to create a class there's only one thing that comes to my mind, the Tuple:
List<Tuple<string, string>> weatherList = new List<string, string>();
weatherList.Add(Tuple.Create("Sunny", "img/sunny.jpg"));
weatherList.Add(Tuple.Create("Rain", "img/Rain.jpg"));
if (WeatherValue == 0) // whatever that is
{
Label1.Text = weatherList[0].Item1;
Image1.ImageUrl = weatherList[0].Item2;
}
You can use a Dictionary
Dictionary<string, string> weather = new Dictionary<string, string>();
values.Add("Sunny", "img/sunny.jpg");
values.Add("Rain", "img/Rain.jpg");
The simplest way to call element in a dictionnary is using foreach loop
foreach (var pair in weather )
{
Console.WriteLine("{0}, {1}",pair.Key,pair.Value);
}
I would like some way to hard code information in C# as follows:
1423, General
5298, Chiro
2093, Physio
9685, Dental
3029, Optics
I would like to then refer to this data as follows:
"The description for category 1423 is " & MyData.GetDescription[1423]
"The id number for General is " & MyData.GetIdNumber("General")
What would be the best way to do this in C#?
Well you could use Tuple<int, string> - but I'd suggest creating a class to store the two values:
public sealed class Category
{
private readonly int id;
public int Id { get { return id; } }
private readonly string description;
public string Description { get { return description; } }
public Category(int id, string description)
{
this.id = id;
this.description = description;
}
// Possibly override Equals etc
}
Then for lookup purposes, you could either have a Dictionary<string, Category> for description lookups and a Dictionary<int, Category> for ID lookups - or if you were confident that the number of categories would stay small, you could just use a List<Category>.
The benefits of having a named type for this over using just a Tuple or simple Dictionary<string, int> and Dictionary<int, string> are:
You have a concrete type you can pass around, use in your data model etc
You won't end up confusing a Category with any other data type which is logically just an int and a string
Your code will be clearer to read when it uses Id and Description properties than Item1 and Item2 from Tuple<,>.
If you need to add another property later, the changes are minimal.
You can use a Dictionary<TKey, TValue>:
var items = new Dictionary<int, string>();
items.Add(1423, "General");
...
var valueOf1423 = items[1423];
var keyOfGeneral = items.FirstOrDefault(x => x.Value == "General").Key;
The example above will throw an exception if there's no item with value "General". To prevent this you could wrap the Dictionary in a custom class and check if the entry exists and returns whatever you need.
Note that the value is not unique, a Dictonary allows you to store the same values with different keys.
A wrapper class could look something like this:
public class Category {
private Dictionary<int, string> items = new Dictionary<int,, string>();
public void Add(int id, string description) {
if (GetId(description <> -1)) {
// Entry with description already exists.
// Handle accordingly to enforce uniqueness if required.
} else {
items.Add(id, description);
}
}
public string GetDescription(int id) {
return items[id];
}
public int GetId(string description) {
var entry = items.FirstOrDefault(x => x.Value == description);
if (entry == null)
return -1;
else
return entry.Key;
}
}
Rather than making numerous overloads of a class constructor, I would like to pass in a Dictionary to dynamically set variables.
// Class definition
public class Project
{
public DateTime LastModified;
public string LoanName;
public string LoanNumber;
public int LoanProgram;
public string ProjectAddress;
...
// Project class constructor
public Project(Dictionary<string, object> Dict)
{
foreach (KeyValuePair<string, object> entry in Dict)
{
// ie, when the Key is "LoanName", this.LoanName is set
this.(entry.Key) = entry.Value; // <-- Does not compile, obviously
}
}
}
// application code
...
Dictionary<string, object> dict = new Dictionary<string,object>();
dict.Add("LoanName", "New Loan Name");
dict.Add("LoanProgram", 1);
dict.Add("ProjectAddress", "123 Whatever Way");
Project p = new Project(dict);
...
In the constructor, is there any way to use the Dictionary Key (a string) to determine what class member to set? Can this be done using reflection somehow?
The fields are already public... why not just use object initialization syntax?
var p = new Project() {
LoanName = "New Loan Name",
LoanProgram = 1,
ProjectAddress = "123 Whatever Way"
};
public class Project
{
public DateTime LastModified;
public string LoanName;
public string LoanNumber;
public int LoanProgram;
public string ProjectAddress;
...
// Project class constructor
public Project(Dictionary<string, object> Dict)
{
foreach (KeyValuePair<string, object> entry in Dict)
{
this.GetType().GetProperty(entry.Key).SetValue(this, entr.Value, null);
}
}
}
This seems like a maintenance nightmare but you can look up the property this way.
var prop = typeof(Project).GetProperty(entry.Key);
Then you could set the value like this.
prop.SetValue(this, entry.Value);
You get no compile time type checking this way though.
I would suggest looking into default parameters.
e.g.
public Project(loanName = null, lastModified = null, loanNumber = null, loanProgram = 0, projectAddress = null)
{
//Set them in here
}
I would also recommend using public properties instead of public fields.
e.g.
public DateTime LastModified { get; private set; } //Makes it so only inside the class LastModified can be set