I want do achieve a pretty simple task, but the thing is to do this in a nice, simple way. We all want to write pretty code that is easy to maintain, quick to understand. I have a problem that experienced C# developers may help me with.
I want to create a dictionary, where keys (string[]) are names of enum values and values are their ecorresponding enum values. If this is confusing, let me give you a short example:
enum Animals
{
Dog,
Cat,
Fish
}
Dictionary<string, Animals> result = new Dictionary<string, Animals>()
{
{ "Dog", Animals.Dog },
{ "Cat", Animals.Cat },
{ "Fish", Animals.Fish }
};
Here is my approach:
a little extension:
public static IEnumerable<T> GetValues<T>() => Enum.GetValues(typeof(T)).Cast<T>();
and then the construction:
var result = Utils
.GetValues<Animals>()
.ToDictionary(x => x.ToString(), x => x);
How would you, experienced devs, approach this problem to write it in a clearer way? Or perhaps there is a trick with enums that would enable a quick lookup like "give me an enum which name satisfies my condition".
To take a string and convert it to its matching enum value, or even fail if there is no matching enum value you should use Enum.TryParse:
Animals animal;
if (Enum.TryParse("Dog", out animal))
// animal now contains Animals.Dog
else
// animal "undefined", there was no matching enum value
The Parse method of the Enum type is what I think you are looking for.
var value = Enum.Parse(typeof(T), "Dog");
Related
Before adding a new tuple, I want to check if a list already contains that tuple and avoiding adding it to the list again, how would I got about doing this? I'm aware for integers and strings you would just write list.Contains(2) or list.Contains("2"), but i'm not sure what syntax to use when checking for tuples.
I've tried these two so far (snippets). (combination is a list of tuples<char, char>)
if(!combinations.Contains(Tuple<char, char>(s[i], chr)))
{
combinations.Add(new Tuple<char, char>(s[i], chr));
}
if(!combinations.Contains(Tuple<char, char> s[i], chr))
{
combinations.Add(new Tuple<char, char>(s[i], chr));
}
Adding works fine so I thought it would be the same when comparing. Any help with syntax or logic would be great, thanks :)
Tuples already implement the appropriate equality, so you shouldn't need to do anything except create the value, and then use .Contains. However:
you may prefer ValueTuple<...> over Tuple<...>, and
if order doesn't matter, you may prefer HashSet<T>, which handles uniqueness internally
For example:
// note that (char, char) is a ValueTuple<char, char>
private readonly HashSet<(char,char)> combinations = new();
//...
combinations.Add((x, y)); // adds the x/y tuple if it doesn't exist
You can also name the parts here:
private readonly HashSet<(char X,char Y)> combinations = new();
which will allow you to use .X and .Y on values, via compiler voodoo.
In C#, you can use the Contains() method to check if a list contains a specific tuple. Here is an example:
// List of tuples
var tupleList = new List<(char, char)>()
{
('a', 'b'),
('c', 'd'),
('e', 'f')
};
// Tuple to search for
var searchTuple = ('a', 'b');
// Check if the list contains the tuple
if (tupleList.Contains(searchTuple))
{
Console.WriteLine("The list contains the tuple");
}
else
{
Console.WriteLine("The list does not contain the tuple");
}
I have a car class which needs a brand, a type, and the make, for example, SUV, coupe, sedan. I made an enum class for these types. I want to instantiate a new car which needs these arguments. I have to import these data from a text file. The text file contains this: &Peugeot*406%sedan$2002/110. I split the pieces of information into a string array but don't know how to get the make of the car. I hope you understand my problem here is the code :
Car car = new Car(data[0],data[1],int.Parse(data[2]),int.Parse(data[3]),int.Parse(data[4]));
You need to parse the strings into enum equivalents. It is better to use TryParse to avoid exceptions.
Here's a simple example especially written for you :)
enum AutoBrand { Skoda, Toyota, BMW};
enum AutoType { SUV, SEDAN, HATCHBACK};
static void Main(string[] args)
{
string[] strAutoBrands = new string[] { "Skoda", "Toyota", "BMW" };
string[] strAutoTypes = new string [] { "SUB", "SEDAN", "HATCHBACK" };
foreach(var autoBrandVal in strAutoBrands)
{
AutoBrand b = (AutoBrand) Enum.Parse(typeof(AutoBrand), autoBrandVal);
Console.WriteLine($"Auto brand is: {b}");
}
}
Enums are typically used to define a set of constants to use instead of "magic numbers" to make code mode human-readable. They may not be appropriate to use for string-based data like make and model.
However, if you have a string and want to find the equivalent Enum value, use Enum.Parse:
Car car = new Car(
Enum.Parse(typeof(Make),data[0]),
Enum.Parse(typeof(Model),data[1]),
int.Parse(data[2]),
int.Parse(data[3]),
int.Parse(data[4]));
Note that you should add appropriate error hendling, etc. to deal with invalid string values.
I have an array of some types
private string[] linkTypes = {
"dog",
"cat",
// and so on ..
};
Yes, I could use an enum but in this case it has to be an array of
strings.
So now I have a List of objects called "LinkElement"
private List<LinkElement> links = new List<LinkElement>();
and these objects have a string property called "Type"
string linkType = links[index].Type;
If linkTypes contains the elements "dog" and "cat", my links can only have "dog" or "cat" as their type.
I want to sort the list "links" by the order of linkTypes.
Means the lists order contains the links with having the type "dog" first and after that the links with the type "cat" come up.
List<LinkElement> sortedLinks = ; // sort links
for (int i = 0; i < sortedLinks.Count; i++)
{
LinkElement currentLink = sortedLinks[i];
Console.WriteLine(currentLink.Type);
}
// Write down dogs first, cats after
Can someone help me out?
Assuming linkTypes (the private string array) is in the same class as links (the list of LinkElement), you can use LINQ's OrderBy with a simple lambda expression:
var sortedLinks = links.OrderBy(le => Array.IndexOf(linkTypes, le.linkType)).ToList()
Comparisons such as "alphabetical order" (string) "bigger number" (numerical types) etc. are accomplished using the IComparable interface. You can implement this interface in your custom class to make instances sort themselves any way you like. Read up on the interface here:
https://msdn.microsoft.com/en-us/library/4d7sx9hd(v=vs.110).aspx
If you have a fixed number of types, then you could use a quick helper method to return an integer for each object depending on its type, and compare the returned integers from each object to determine which one "comes first."
Implement either the IComparer or the IComparable interface. The downside of using the IComparable is that this has to be implemented by the class which is targeted for sorting, which means that in case you want to sort it a different way elsewhere in your code, you will not be able to do so using this mechanism. On the other hand, IComparer can be decoupled from the target class and implemented in multiple ways if you choose to, and depending on the sorting criteria in different parts of your application, you could apply one of these IComparer classes as needed.
https://support.microsoft.com/en-us/help/320727/how-to-use-the-icomparable-and-icomparer-interfaces-in-visual-c
I use System.Linq.Dynamic to order an items list.
items = items.AsQueryable().OrderBy("Name ASC");
To my surprise, lowercase names gets ordered after the capital cased names, so the items are returned something like this.
Ape
Cat
Dog
alligator
ant
beetle
I expected this order:
alligator
ant
Ape
beetle
Cat
Dog
Is there a way to get the correct order? Checked all method signatures for OrderBy and googled around, but nada.
You do not need to create a custom comparer because there's already a StringComparer class which derives from IComparer.
words.OrderBy (x => x, StringComparer.OrdinalIgnoreCase)
This way, you do not need to create different IComparer implementations if you wanted to use other string comparison methods, like StringComparer.InvariantCultureIgnoreCase.
However, this might be desirable depending on your situation. For example, I do have multiple extension methods defined in LINQPad, like OrderBySelfInvariantCultureIgnoreCase, because it is convenient to use this with code completion rather than typing out the equivalent code by hand:
public static IEnumerable<string> OrderBySelfInvariantCultureIgnoreCase(this IEnumerable<string> source)
{
return source.OrderBy (x => x, StringComparer.InvariantCultureIgnoreCase);
}
You must create a custom comparer, such as:
public void Main()
{
String[] words = { "aPPLE", "AbAcUs", "bRaNcH", "BlUeBeRrY", "ClOvEr", "cHeRry" };
var sortedWords = words.OrderBy(a => a, new CaseInsensitiveComparer());
ObjectDumper.Write(sortedWords);
}
public class CaseInsensitiveComparer : IComparer<string>
{
public int Compare(string x, string y)
{
return string.Compare(x, y, StringComparison.OrdinalIgnoreCase);
}
}
Found # https://code.msdn.microsoft.com/SQL-Ordering-Operators-050af19e
I have faced the same issue and found no easy solution over the internet. Then I was trying in many ways and finally got a very simple way. It completely worked for me. My solution is
string sort = "Name ASC";
string[] data = sort.Split(" ");
items.OrderBy($"{data[0].ToUpper() data[1]}");
Now the output is alligator,
ant,
Ape,
beetle,
Cat,
Dog
Let's say a program like this:
class MyClass
{
public int Numbers;
public char Letters;
}
class Program
{
static void Main()
{
var mc = new MyClass[5];
for (var i = 0; i < 5; i++)
{
mc[i].Numbers = i + 1;
mc[i].Letters = (char) (i + 65);
}
}
}
Now, let's suppose an 'X' method that requires ALL the numbers contained in the object mc, in a separate array, that's sent as a parameter.
My first idea is a for, a new integers array, and copy one by one onto its respective position. But, what if the MyClass gets different, now it has strings and floats, and I wanna pull out the strings, now the for has to be completely redefined in its inside part to create the needed array for another 'X' method.
I know of cases where Linq helps a lot, for example, generics for Sum, Average, Count and another numeric functions, and of course, it's combination with lambda expressions.
I'm wondering if something similar exists to make the above arrays of MyClass (and anothers of course) in a faster-generic way?
If you want to use LINQ, you can do something like the following:
int [] numbers = mc.Select<MyClass, int>(m => mc.Number).ToArray();
To make it more generic than that, it gets a bit more complicated, and you may need reflection, or dynamic objects. A simple example with reflection would be:
private TValue[] ExtractFields<TClass, TValue>(TClass[] classObjs, string fieldName)
{
FieldInfo fInfo = typeof(TClass).GetField(fieldName, BindingFlags.Public | BindingFlags.Instance);
if (fInfo != null && fInfo.FieldType.Equals(typeof(TValue)))
return classObjs.Select<TClass, TValue>(c => (TValue)fInfo.GetValue(c)).ToArray();
else
throw new NotSupportedException("Unidentified field, or different field type");
}
And then just call it like:
int [] fields = ExtractField<MyClass, int>(mc, "Number");
If you are using C# 4.0, then you may use dynamic
class MyClass
{
public dynamic Numbers;
public char Letters;
}
EDIT: based on comments
I am not sure if this is what you want:
int[] arr = mc.Select(a => a.Numbers).ToArray<int>();
or without casting
int[] arr = mc.Select(a => a.Numbers).ToArray();
Why not just use Dictionary<int, char>, or if the data type is unknown then simply Dictionary<object, object>
If your goal is to generate a new array which is detached from the original array, but contains data copied from it, the most generic thing you could do would be to define a method like:
T my_array[]; // The array which holds the real things
U[] CopyAsConvertedArray<U>(Func<T,U> ConversionMethod);
That would allow one to generate a new array which extracts items from the original using any desired method.