Equality of two structs in C# - c#

I look for an equality between two instances of this struct.
public struct Serie<T>
{
T[] X;
double[] Y;
public Serie(T[] x, double[] y)
{
X = x;
Y = y;
}
public override bool Equals(object obj)
{
return obj is Serie<T> && this == (Serie<T>)obj;
}
public static bool operator ==(Serie<T> s1, Serie<T> s2)
{
return s1.X == s2.X && s1.Y == s2.Y;
}
public static bool operator !=(Serie<T> s1, Serie<T> s2)
{
return !(s1 == s2);
}
This doesn't work. What am I missing?
double[] xa = { 2, 3 };
double[] ya = { 1, 2 };
double[] xb = { 2, 3 };
double[] yb = { 1, 2 };
Serie<double> A = new Serie<double>(xa, ya);
Serie<double> B = new Serie<double>(xb, yb);
Assert.AreEqual(A, B);

You're comparing the array references rather than their contents. ya and yb refer to different arrays. If you want to check the contents of the arrays, you'll have to do so explicitly.
I don't think there's anything built into the framework to do that for you, I'm afraid. Something like this should work though:
public static bool ArraysEqual<T>(T[] first, T[] second)
{
if (object.ReferenceEquals(first, second))
{
return true;
}
if (first == null || second == null)
{
return false;
}
if (first.Length != second.Length)
{
return false;
}
IEqualityComparer comparer = EqualityComparer<T>.Default;
for (int i = 0; i < first.Length; i++)
{
if (!comparer.Equals(first[i], second[i]))
{
return false;
}
}
return true;
}
As an aside, your structs are sort of mutable in that the array contents can be changed after the struct is created. Do you really need this to be a struct?
EDIT: As Nick mentioned in the comments, you should really override GetHashCode as well. Again, you'll need to get the contents from the arrays (and again, this will cause problems if the arrays get changed afterwards). Similar utility method:
public static int GetHashCode<T>(T[] array)
{
if (array == null)
{
return 0;
}
IEqualityComparer comparer = EqualityComparer<T>.Default;
int hash = 17;
foreach (T item in array)
{
hash = hash * 31 + comparer.GetHashCode(item);
}
return hash;
}

I don't think there's anything built into the framework to do that for you, I'm afraid
In 4.0, there is:
StructuralComparisons.StructuralEqualityComparer.Equals(firstArray, secondArray);

You should compare the contents of the Array in your Equality logic ...
Also, it is recommended that you implement IEquatable<T> interface on your struct, as this prevents boxing/unboxing issues in some cases.
http://blogs.msdn.com/jaredpar/archive/2009/01/15/if-you-implement-iequatable-t-you-still-must-override-object-s-equals-and-gethashcode.aspx

The part s1.Y == s2.Y tests if they are 2 references to the same array instance, not if the contents are equal. So despite the title, this question is actually about equality between array(-reference)s.
Some additional advice: Since you are overloading you should design Serie<> as immutable and because of the embedded array I would make it a class instead of a struct.

Calling == performs reference equality on arrays - they don't compare the contents of their elements. This basically means that a1 == a2 will only return true if the exact same instance - which isn't what you want, I think..
You need to modify your operator == to compere the contents of the x array, not it's reference value.
If you're using .NET 3.5 (with link) you can do:
public static bool operator ==(Serie<T> s1, Serie<T> s2)
{
return ((s1.X == null && s2.X == null) || s1.X.SequenceEquals( s2.X ))
&& s1.Y == s2.Y;
}
If you need to do deep comparison (beyond references), you can supply SequenceEquals with a custom IEqualityComparer for the type of T.
You probably should also consider implementing the IEquatable<T> interface for your struct. It will help your code work better with LINQ and other parts of the .NET framework that perform object comparisons.

You can create a private accessor for your struct and use CollectionAssert:
[TestMethod()]
public void SerieConstructorTest()
{
double[] xa = { 2, 3 };
double[] ya = { 1, 2 };
double[] xb = { 2, 3 };
double[] yb = { 1, 2 };
var A = new Serie_Accessor<double>(xa, ya);
var B = new Serie_Accessor<double>(xb, yb);
CollectionAssert.AreEqual(A.X, B.X);
CollectionAssert.AreEqual(A.Y, B.Y);
}
This code works fine.
References:
CollectionAssert.AreEqual Method
How to create private accessor

Related

Compare two lists of nodes with total match

I create the two lists of object, but cannot do total match value which is
var inputNodes = new List<nodes>()
{
new node() { nodeName= "D100", DataLength = 1 },
new node() { nodeName= "D101", DataLength = 1 },
new node() { nodeName= "D102", DataLength = 1 },
new node() { nodeName= "D103", DataLength = 1 },
new node() { nodeName= "D104", DataLength = 1 },
new node() { nodeName= "D105", DataLength = 1 },
new node() { nodeName = "D106", DataLength = 1 }
};
var inputNodes2 = new List<nodes>()
{
new node() { nodeName= "D100", DataLength = 1 },
new node() { nodeName= "D101", DataLength = 1 },
new node() { nodeName= "D102", DataLength = 1 },
new node() { nodeName= "D103", DataLength = 1 },
new node() { nodeName= "D104", DataLength = 1 },
new node() { nodeName= "D105", DataLength = 1 },
new node() { nodeName= "D106", DataLength = 1 }
};
I try to use check var isEqual = inputNodes.SequenceEqual(inputNodes2)
It return false and I don't want to use loop or list.select function
any idea for that ?
It seems to me that you are not familiar with the concept of equality, and how you can change the definition of equality to your definition. Hence I'll explain default equality and how to write an equality comparer that holds your idea of equality.
By default equality of objects is reference equality: two objects are equal if they refer to the same object:
Node A = new Node {...}
Node X = A;
Node Y = A;
Objects X and Y refer to the same object, and thus:
Assert(X == Y)
IEqualityComparer<Node> nodeComparer = EqualityComparer<Node>.Default;
Assert(nodeComparer.Equals(x, y));
However, in your case inputNodes[0] and inputNodes2[0] do not refer to the same object. Hence they are not equal Nodes, and thus SequenceEqual will return false.
You don't want to use the standard Equality comparison, you want a special one. According to your definition, two Nodes are equal, if the properties of the Nodes are equal. This definition of equality is called "value equality", as contrast to "reference equality"
Because you don't want to use the default reference equality, you'll have to write the equality comparer yourself. The easiest way to do this, is to derive a class from EqualityComparer.
public class NodeComparer : EqualityComparer<Node>
{
public static IEqualityComparer<Node> ValueComparer {get} = new NodeComparer();
public override bool Equals(Node x, Node y) {... TODO: implement}
public override int GetHashCode(node x) {... TODO: implement}
}
Usage will be as follows:
IEnumerable<Node> inputNodes1 = ...
IEnumerable<Node> inputNodes2 = ...
IEqualityComparer<Node> nodeComparer = NodeComparer.ValueComparer;
bool equalInputNodes = inputNodes1.SequenceEqual(inputNodes2, nodeComparer);
Equals
The definition depends on YOUR definition of equality. You can use any definition you need. In your case, you chose a straightforward "compare by value":
public override bool Equals(Node x, Node y)
{
// The following statements are almost always the same for every equality
if (x == null) return y == null; // true if both null
if (y == null) return false; // because x not null
if (Object.ReferenceEquals(x, y)) return true; // because same object
if (x.GetType() != y.GetType()) return false; // different types
In some occassions, these statements might be different. For example, if you want to create a string comparer where a null string equals an empty string:
string x = null;
string y = String.Empty;
IEqualityComparer<string> stringComparer = MyStringComparer.EmptyEqualsNull;
Assert(stringComparer.Equals(x, y));
Or, if you think that Teachers are Persons, than in some cases you might want that when you compare a Teacher with a Person, you might not want to check on the type.
But all in all, most comparers will use these four initial lines.
Continuing your equality:
return x.NodeName == y.NodeName
&& x.DataLength == y.DataLength;
To be prepared for the future, consider the following:
private static readonly IEqualityComparer<string> nodeNameComparer = StringComparer.Default;
and in your equals method:
return nodeNameComparer.Equals(x.NodeName, y.NodeName)
&& x.DataLength == y.DataLength;
So if in future you want to do a case insensitive string comparison, you only have to change the static declaration of your nodeNameComparer:
private static readonly IEqualityComparer<string> nodeNameComparer = StringComparer.OrdinalIgnoreCase;
GetHashCode
GetHashCode is meant to create a fast method to separate most unequal objects. This is useful, if your Node has two hundred properties, and you know, that if they have equal value for property Id, that very likely all other elements will be equal.
Note that I use "very likely". It is not guaranteed for 100% that if X has the same hashcode as Y, that X will equal Y. But you can be certain:
if X has a different hashcode than Y, then they will not be equal.
The only requirement for GetHashCode is that if X equals Y, then MyComparer.GetHashCode(X) equals MyComparer.GetHashCode(Y);
If X is not equal to Y, then you don't know whether their hashcodes will be different, although it would be nice if so, because code will be more efficient.
GetHashcode is meant to be fast, it doesn't have to check everything, it might be handy if it separates most elements, but it does not have to be a complete equality check.
How about this one:
public override int GetHashCode(Node x)
{
if (x == null) return 874283; // just a number
// for HashCode only use the NodeName:
return x.NodeName.GetHashCode();
}
Or, if you use a string comparer in method Equals for NodeName:
private static readonly IEqualityComparer<string> nodeNameComparer = StringComparer.OrdinalIgnoreCase;
// this comparer is used in Equals
public override int GetHashCode(Node x)
{
if (x == null) return 874283; // just a number
return nodenameComparer.GetHashCode(x.NodeName);
}
So if in future you change the comparison method for the nodename to CurrentCulture, then both Equals and GetHashCode will use the proper comparer.
Node a = new Node {nodeName= "X", DataLength = 1 };
Node b = new Node {nodeName= "X", DataLength = 1 };
Node c = new Node {nodeName= "X", DataLength = 2 };
Node d = new Node {nodeName= "Y", DataLength = 1 };
It is easy to see, that b equals a. c and d are different than a.
Although c is different, the comparer will return the same hashcode as for a.
So GetHashCode is not enough for exact equality, but a good GetHashCode will separate most different objects.
Use a IEqualityComparer like below.
class NodeComparer : IEqualityComparer<node>
{
public bool Equals(node? x, node? y)
{
if(x == null && y == null){
return true;
}
if(x == null || y == null)
{
return false;
}
return string.Equals(x.nodeName, y.nodeName) && x.DataLength == y.DataLength;
}
public int GetHashCode([DisallowNull] node obj)
{
return obj.nodeName.GetHashCode() * obj.DataLength.GetHashCode();
}
}
and then use it in the SequenceEquals
inputNodes.SequenceEqual(inputNodes2, new NodeComparer());

How to use a primitive list or List as a key of a dictionary in C#

I'm trying to use an int array as key in C# and the behaviour I'm seeing is unexpected (for me).
var result = new Dictionary<int[], int>();
result[new [] {1, 1}] = 100;
result[new [] {1, 1}] = 200;
Assert.AreEqual(1, result.Count); // false is 2
It seems the same with List too.
var result = new Dictionary<List<int>, int>();
result[new List<int> { 1, 1 }] = 100;
result[new List<int> { 1, 1 }] = 200;
Assert.AreEqual(1, result.Count); // false is 2
I'm expecting the Dictionary to use Equals to decide if a Key is present in the map. This doesn't seem to be the case.
Can someone explain why and how I can get this sort of behaviour to work?
.NET lists and arrays do not have a built-in equality comparison, so you need to provide your own:
class ArrayEqComparer : IEqualityComparer<int[]> {
public static readonly IEqualityComparer<int[]> Instance =
new ArrayEqComparer();
public bool Equals(int[] b1, int[] b2) {
if (b2 == null && b1 == null)
return true;
else if (b1 == null | b2 == null)
return false;
return b1.SequenceEqual(b2);
}
public int GetHashCode(int[] a) {
return a.Aggregate(37, (p, v) => 31*v + p);
}
}
Now you can construct your dictionary as follows:
var result = new Dictionary<int[],int>(ArrayEqComparer.Instance);
The Dictionary class allows a custom equality comparer as a dictionary comparer. Implement IEqualityComparer> by providing a GetHashCode(IList obj) by returning the xor (the ^ operator) of all list elements (0 ^ first ^ second...) and Equals(IList x, IList y) by using Linq.Enumerable.SequenceEquals. Then pass an instance of that to the Dictionary constructor.
You are passing new object (array or list) as a key. As a new object it has a different reference so it is accepted as new key.

Compare a set of three strings with another

I am making a list of unique "set of 3 strings" from some data, in a way that if the 3 strings come together they become a set, and I can only have unique sets in my list.
A,B,C
B,C,D
D,E,F and so on
And I keep adding sets to the list if they do not exist in the list already, so that if I encounter these three strings together {A,B,C} I wont put it in the list again. So I have 2 questions. And the answer to second one actually depends on the answer of the first one.
How to store this set of 3 string, use List or array or concatenate them or anything else? (I may add it to a Dictionary to record their count as well but that's for later)
How to compare a set of 3 strings with another, irrespective of their order, obviously depending on the structure used? I want to know a proper solution to this rather than doing everything naively!
I am using C# by the way.
Either an array or a list is your best bet for storing the data, since as wentimo mentioned in a comment, concatenating them means that you are losing data that you may need. To steal his example, "ab" "cd "ef" concatenated together is the same as "abcd" "e" and "f" concatenated, but shouldn't be treated as equivalent sets.
To compare them, I would order the list alphabetically, then compare each value in order. That takes care of the fact that the order of the values doesn't matter.
A pseudocode example might look like this:
Compare(List<string> a, List<string> b)
{
a.Sort();
b.Sort();
if(a.Length == b.Length)
{
for(int i = 0; i < a.Length; i++)
{
if(a[i] != b[i])
{
return false;
}
}
return true;
}
else
{
return false;
}
}
Update
Now that you stated in a comment that performance is an imporatant consideration since you may have millions of these sets to compare and that you won't have duplicate elements in a set, here is a more optimized version of my code, note that I no longer have to sort the two lists, which will save quite a bit of time in executing this function.
Compare(List<string> a, List<string> b)
{
if(a.Length == b.Length)
{
for(int i = 0; i < a.Length; i++)
{
if(!b.Contains(a[i]))
{
return false;
}
}
return true;
}
else
{
return false;
}
}
DrewJordan's approach of using a hashtable is still probably than my approach, since it just has to sort each set of three and then can do the comparison to your existing sets much faster than my approach can.
Probably the best way is to use a HashSet, if you don't need to have duplicate elements in your sets. It sounds like each set of 3 has 3 unique elements; if that is actually the case, I would combine a HashSet approach with the concatenation that you already worked out, i.e. order the elements, combine with some separator, and then add the concatenated elements to a HashSet which will prevent duplicates from ever occuring in the first place.
If your sets of three could have duplicate elements, then Kevin's approach is what you're going to have to do for each. You might get some better performance from using a list of HashSets for each set of three, but with only three elements the overhead of creating a hash for each element of potentially millions of sets seems like it would perform worse then just iterating over them once.
here is a simple string-wrapper for you:
/// The wrapper for three strings
public class StringTriplet
{
private List<string> Store;
// accessors to three source strings:
public string A { get; private set; }
public string B { get; private set; }
public string C { get; private set; }
// constructor (need to feel internal storage)
public StringTriplet(string a, string b, string c)
{
this.Store = new List<string>();
this.Store.Add(a);
this.Store.Add(b);
this.Store.Add(c);
// sort is reqiured, cause later we don't want to compare all strings each other
this.Store.Sort();
this.A = a;
this.B = b;
this.C = c;
}
// additional method. you could add IComparable declaration to the entire class, but it is not necessary in your task...
public int CompareTo(StringTriplet obj)
{
if (null == obj)
return -1;
int cmp;
cmp = this.Store.Count.CompareTo(obj.Store.Count);
if (0 != cmp)
return cmp;
for (int i = 0; i < this.Store.Count; i++)
{
if (null == this.Store[i])
return 1;
cmp = this.Store[i].CompareTo(obj.Store[i]);
if ( 0 != cmp )
return cmp;
}
return 0;
}
// additional method. it is a good practice : override both 'Equals' and 'GetHashCode'. See below..
override public bool Equals(object obj)
{
if (! (obj is StringTriplet))
return false;
var t = obj as StringTriplet;
return ( 0 == this.CompareTo(t));
}
// necessary method . it will be implicitly used on adding values to the HashSet
public override int GetHashCode()
{
int res = 0;
for (int i = 0; i < this.Store.Count; i++)
res = res ^ (null == this.Store[i] ? 0 : this.Store[i].GetHashCode()) ^ i;
return res;
}
}
Now you could just create hashset and add values:
var t = new HashSet<StringTriplet> ();
t.Add (new StringTriplet ("a", "b", "c"));
t.Add (new StringTriplet ("a", "b1", "c"));
t.Add (new StringTriplet ("a", "b", "c")); // dup
t.Add (new StringTriplet ("a", "c", "b")); // dup
t.Add (new StringTriplet ("1", "2", "3"));
t.Add (new StringTriplet ("1", "2", "4"));
t.Add (new StringTriplet ("3", "2", "1"));
foreach (var s in t) {
Console.WriteLine (s.A + " " + s.B + " " + s.C);
}
return 0;
You can inherit from List<String> and override Equals() and GetHashCode() methods:
public class StringList : List<String>
{
public override bool Equals(object obj)
{
StringList other = obj as StringList;
if (other == null) return false;
return this.All(x => other.Contains(x));
}
public override int GetHashCode()
{
unchecked
{
int hash = 19;
foreach (String s in this)
{
hash = hash + s.GetHashCode() * 31;
}
return hash;
}
}
}
Now, you can use HashSet<StringList> to store only unique sets

Array comprasion as Dictionary keys in C#

I want to create class representing n-dimensional array, but where is a commutative access to its elements. e.g: a[new[] {4, 7, 55}] == a[new[] {55, 4, 7}]
I write this code, where I implement interface IEqualityComparer in order to compare keys (which are arrays) by their real content, but not refs.
using System;
using System.Collections.Generic;
using System.Linq;
class NArray
{
public int this[int[] x]
{
get
{
Array.Sort(x);
return array[x];
}
set
{
Array.Sort(x);
array[x] = value;
}
}
public void Remove(int[] x)
{
Array.Sort(x);
array.Remove(x);
}
Dictionary<int[], int> array = new Dictionary<int[], int>(new ArrCmpr());
}
class ArrCmpr : IEqualityComparer<int[]>
{
public bool Equals(int[] a, int[] b)
{
return a.Length == b.Length && Enumerable.Range(0, a.Length).All(i => a[i] == b[i]);
}
public int GetHashCode(int[] a)
{
return a.GetHashCode();
}
}
But when I start to use this class I encounter an exception: "System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary." This exception occurs in next both cases when I try to output the element to console:
NArray a = new NArray();
a[new[] { 1, 3, 2 }] = 4;
Console.WriteLine(a[new[] { 3, 2, 1 }]); //error
 
NArray b = new NArray();
b[new[] { 1, 2, 3 }] = 4;
Console.WriteLine(b[new[] { 1, 2, 3 }]); //error
So what is the cause of that problem and how could I fix it?
That's because your implementation of GetHashCode is incorrect: two different arrays with the same items in the same order usually won't have the same hashcode (because the values are not taken into account), so Equals is never called.
You need an implementation of GetHashCode that takes the values in the array into account:
class ArrCmpr : IEqualityComparer<int[]>
{
public bool Equals(int[] a, int[] b)
{
return a.SequenceEqual(b);
}
public int GetHashCode(int[] a)
{
return a.Aggregate(0, (acc, i) => unchecked(acc * 457 + i * 389));
}
}
To me seems that GetHashCode have to be changed as it simply returns the hash code of Array object, considering the fact that you use NEW hashcode every time will be different, even if content equal.
Since you're using a Dictionary to store your arrays you need to check if the key exists already, and only then can you access it with the [] operator, otherwise if you try to access a key that doesn't exist an exception is thrown
// your get function
if(array.ContainsKey(x))
return array[x];
else // do something like return null
return null;
// your set function
if(array.ContainsKey(x))
array[x] = value;
else
array.Add(x, value);

How to get next (or previous) enum value in C#

I have an enum which is defined like this:
public enum eRat { A = 0, B=3, C=5, D=8 };
So given value eRat.B, I want to get the next one which is eRat.C
The solution I see is (without range checking)
Array a = Enum.GetValues(typeof(eRat));
int i=0 ;
for (i = 0; i < a.GetLength(); i++)
{
if (a.GetValue(i) == eRat.B)
break;
}
return (eRat)a.GetValue(i+1):
Now that is too much complexity, for something that simple. Do you know any better solution?? Something like eRat.B+1 or Enum.Next(Erat.B)?
Thanks
Thanks to everybody for your answers and feedback. I was surprised to get so many of them. Looking at them and using some of the ideas, I came up with this solution, which works best for me:
public static class Extensions
{
public static T Next<T>(this T src) where T : struct
{
if (!typeof(T).IsEnum) throw new ArgumentException(String.Format("Argument {0} is not an Enum", typeof(T).FullName));
T[] Arr = (T[])Enum.GetValues(src.GetType());
int j = Array.IndexOf<T>(Arr, src) + 1;
return (Arr.Length==j) ? Arr[0] : Arr[j];
}
}
The beauty of this approach, that it is simple and universal to use. Implemented as generic extension method, you can call it on any enum this way:
return eRat.B.Next();
Notice, I am using generalized extension method, thus I don't need to specify type upon call, just .Next().
Probably a bit overkill, but:
eRat value = eRat.B;
eRat nextValue = Enum.GetValues(typeof(eRat)).Cast<eRat>()
.SkipWhile(e => e != value).Skip(1).First();
or if you want the first that is numerically bigger:
eRat nextValue = Enum.GetValues(typeof(eRat)).Cast<eRat>()
.First(e => (int)e > (int)value);
or for the next bigger numerically (doing the sort ourselves):
eRat nextValue = Enum.GetValues(typeof(eRat)).Cast<eRat>()
.Where(e => (int)e > (int)value).OrderBy(e => e).First();
Hey, with LINQ as your hammer, the world is full of nails ;-p
Do you really need to generalize this problem? Can you just do this instead?
public void SomeMethod(MyEnum myEnum)
{
MyEnum? nextMyEnum = myEnum.Next();
if (nextMyEnum.HasValue)
{
...
}
}
public static MyEnum? Next(this MyEnum myEnum)
{
switch (myEnum)
{
case MyEnum.A:
return MyEnum.B;
case MyEnum.B:
return MyEnum.C;
case MyEnum.C:
return MyEnum.D;
default:
return null;
}
}
The problem you're dealing with is because you're trying to get an enum to do something it shouldn't. They're supposed to be type safe. Assigning integral values to an enum is allowed so that you can combine them, but if you want them to represent integral values, use classes or structs. Here's a possible alternative:
public static class eRat
{
public static readonly eRatValue A;
public static readonly eRatValue B;
public static readonly eRatValue C;
public static readonly eRatValue D;
static eRat()
{
D = new eRatValue(8, null);
C = new eRatValue(5, D);
B = new eRatValue(3, C);
A = new eRatValue(0, B);
}
#region Nested type: ERatValue
public class eRatValue
{
private readonly eRatValue next;
private readonly int value;
public eRatValue(int value, eRatValue next)
{
this.value = value;
this.next = next;
}
public int Value
{
get { return value; }
}
public eRatValue Next
{
get { return next; }
}
public static implicit operator int(eRatValue eRatValue)
{
return eRatValue.Value;
}
}
#endregion
}
This allows you to do this:
int something = eRat.A + eRat.B;
and this
eRat.eRatValue current = eRat.A;
while (current != null)
{
Console.WriteLine(current.Value);
current = current.Next;
}
You really should only be using enums when you can benefit from their type safety. If you're relying on them to represent a type, switch to constants or to classes.
EDIT
I would suggest you take a look at the MSDN page on Enumeration Design. The first best practice is:
Do use an enumeration to strongly type
parameters, properties, and return
values that represent sets of values.
I try not to argue dogma, so I won't, but here's the problem you're going to face. Microsoft doesn't want you to do what you are trying to do. They explicitly ask you not to do what you are trying to do. The make it hard for you to do what you are trying to do. In order to accomplish what you are trying to do, you have to build utility code to force it to appear to work.
You have called your solution elegant more than once, and it might be if enums were designed in a different way, but since enums are what they are, your solution isn't elegant. I think that chamber music is elegant, but if the musicians didn't have the proper instruments and had to play Vivaldi with sawblades and jugs, it would no longer be elegant, regardless of how capable they were as musicians, or how good the music was on paper.
Works up to "C" since there is no answer on what to return after "D".
[update1]: Updated according to Marc Gravell's suggestion.
[update2]: Updated according to how husayt's wanted - return "A" for the next value of "D".
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Next enum of A = {0}", eRatEnumHelper.GetNextEnumValueOf(eRat.A));
Console.WriteLine("Next enum of B = {0}", eRatEnumHelper.GetNextEnumValueOf(eRat.B));
Console.WriteLine("Next enum of C = {0}", eRatEnumHelper.GetNextEnumValueOf(eRat.C));
}
}
public enum eRat { A = 0, B = 3, C = 5, D = 8 };
public class eRatEnumHelper
{
public static eRat GetNextEnumValueOf(eRat value)
{
return (from eRat val in Enum.GetValues(typeof (eRat))
where val > value
orderby val
select val).DefaultIfEmpty().First();
}
}
Result
Next enum of A = B
Next enum of B = C
Next enum of C = D
Next enum of D = A
Thanks you all, for your inspiration and solutions.
Here are my results, as an extension.
using System;
using System.Linq;
public static class Enums
{
public static T Next<T>(this T v) where T : struct
{
return Enum.GetValues(v.GetType()).Cast<T>().Concat(new[] { default(T) }).SkipWhile(e => !v.Equals(e)).Skip(1).First();
}
public static T Previous<T>(this T v) where T : struct
{
return Enum.GetValues(v.GetType()).Cast<T>().Concat(new[] { default(T) }).Reverse().SkipWhile(e => !v.Equals(e)).Skip(1).First();
}
}
use:
using System;
using System.Linq;
public enum Test { F1, F2, F3 }
public class Program
{
public static void Main()
{
Test t = Test.F3;
Console.WriteLine(t);
Console.WriteLine(t.Next());
Console.WriteLine(t.Previous());
Console.WriteLine("\n");
t = Test.F1;
Console.WriteLine(t);
Console.WriteLine(t.Next());
Console.WriteLine(t.Previous());
}
}
result:
F3
F1
F2
F1
F2
F3
Are you locked into using an enum by something that you have no control over?
If you're not, I'd suggest using an alternative, probably Dictionary<string, int> rat;
If you create a Dictionary and you populate it with your data, enumerating over it is somewhat simpler. Also, it's a clearer mapping of intent-- you're mapping numbers to strings with this enum and you're trying to leverage that mapping.
If you must use the enum, I'd suggest something else:
var rats = new List<eRat>() {eRat.A, eRat.B, eRat.C, eRat.D};
As long as you're adding the values in-order and you keep it in sync, you greatly simplify the act of retrieving the next eRat.
For simple solution, you might just extract array from enum.
eRat[] list = (eRat[])Enum.GetValues(typeof(eRat));
Then you can enumerate
foreach (eRat item in list)
//Do something
Or find next item
int index = Array.IndexOf<eRat>(list, eRat.B);
eRat nextItem = list[index + 1];
Storing the array is better than extracting from enum each time you want next value.
But if you want more beautiful solution, create the class.
public class EnumEnumerator<T> : IEnumerator<T>, IEnumerable<T> {
int _index;
T[] _list;
public EnumEnumerator() {
if (!typeof(T).IsEnum)
throw new NotSupportedException();
_list = (T[])Enum.GetValues(typeof(T));
}
public T Current {
get { return _list[_index]; }
}
public bool MoveNext() {
if (_index + 1 >= _list.Length)
return false;
_index++;
return true;
}
public bool MovePrevious() {
if (_index <= 0)
return false;
_index--;
return true;
}
public bool Seek(T item) {
int i = Array.IndexOf<T>(_list, item);
if (i >= 0) {
_index = i;
return true;
} else
return false;
}
public void Reset() {
_index = 0;
}
public IEnumerator<T> GetEnumerator() {
return ((IEnumerable<T>)_list).GetEnumerator();
}
void IDisposable.Dispose() { }
object System.Collections.IEnumerator.Current {
get { return Current; }
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return _list.GetEnumerator();
}
}
Instantiate
var eRatEnum = new EnumEnumerator<eRat>();
Iterate
foreach (eRat item in eRatEnum)
//Do something
MoveNext
eRatEnum.Seek(eRat.B);
eRatEnum.MoveNext();
eRat nextItem = eRatEnum.Current;
Judging from your description, you don't really want an enum. You're stretching enum beyond its capabilities. Why not create a custom class that exposes the values you need as properties, while keeping them in OrderedDictionary.
Then getting a next/previous one would be trivial.
--update
If you want to enumerate differently on the collection based in the context, make that explicit part of your design.
Encapsulate the items within a class, and have few methods each returning IEnumerable where, T is your desired type.
For example
IEnumerable<Foo> GetFoosByBar()
IEnumerable<Foo> GetFoosByBaz()
etc...
You could simplify it and generalize it some:
static Enum GetNextValue(Enum e){
Array all = Enum.GetValues(e.GetType());
int i = Array.IndexOf(all, e);
if(i < 0)
throw new InvalidEnumArgumentException();
if(i == all.Length - 1)
throw new ArgumentException("No more values", "e");
return (Enum)all.GetValue(i + 1);
}
EDIT:
Note that if your enum contains duplicate values (synonymous entries), then this (or any other technique listed here) will fail, given one of those values. For instance:
enum BRUSHSTYLE{
SOLID = 0,
HOLLOW = 1,
NULL = 1,
HATCHED = 2,
PATTERN = 3,
DIBPATTERN = 5,
DIBPATTERNPT = 6,
PATTERN8X8 = 7,
DIBPATTERN8X8 = 8
}
Given either BRUSHSTYLE.NULL or BRUSHSTYLE.HOLLOW, the return value would be BRUSHSTYLE.HOLLOW.
<leppie>
Update: a generics version:
static T GetNextValue<T>(T e)
{
T[] all = (T[]) Enum.GetValues(typeof(T));
int i = Array.IndexOf(all, e);
if (i < 0)
throw new InvalidEnumArgumentException();
if (i == all.Length - 1)
throw new ArgumentException("No more values", "e");
return all[i + 1];
}
</leppie>
#leppie:
Your generic version allows one to accidentally pass a non-enum value, which will be caught only at run-time. I had originally written it as a generic, but when the compiler rejected where T : Enum, I took it out and realized that I wasn't gaining much from generics anyway. The only real drawback is that you have to cast the result back to your specific enum type.
Hope this part of my code helps you:
public enum EGroupedBy
{
Type,
InterfaceAndType,
Alpha,
_max
}
private void _btnViewUnit_Click(object sender, EventArgs e)
{
int i = (int)GroupedBy;
i = (i + 1) % (int)EGroupedBy._max;
GroupedBy = (EGroupedBy) i;
RefreshUnit();
}
Old post, but I have an alternative solution
//Next with looping
public static Enum Next(this Enum input)
{
Array Arr = Enum.GetValues(input.GetType());
int j = Array.IndexOf(Arr, input) + 1;
return (Arr.Length == j) ? (Enum)Arr.GetValue(0) : (Enum)Arr.GetValue(j);
}
//Previous with looping
public static Enum Prev(this Enum input)
{
Array Arr = Enum.GetValues(input.GetType());
int j = Array.IndexOf(Arr, input) - 1;
return (j == -1) ? (Enum)Arr.GetValue(Arr.Length -1) : (Enum)Arr.GetValue(j);
}
And when you need to use it, just do a cast
BootstrapThemeEnum theme = BootstrapThemeEnum.Info;
var next = (BootstrapThemeEnum)theme.Next();
my enum
public enum BootstrapThemeEnum
{
[Description("white")]
White = 0,
[Description("default")]
Default = 1,
[Description("info")]
Info = 2,
[Description("primary")]
Primary = 3,
[Description("success")]
Success = 4,
[Description("warning")]
Warning = 5,
[Description("danger")]
Danger = 6,
[Description("inverse")]
Inverse = 7
}
I can think of 2 things:
eRat.B+3
Enum.Parse(typeof(((int)eRat.B)+3)
var next = (eRat)((int)someRat + 3);
Seems like an abuse of the enum class to me - but this would do it (assuming that calling Next on the last value would cause wrap-around):
public static eRat Next(this eRat target)
{
var nextValueQuery = Enum.GetValues(typeof(eRat)).Cast<eRat>().SkipWhile(e => e != target).Skip(1);
if (nextValueQuery.Count() != 0)
{
return (eRat)nextValueQuery.First();
}
else
{
return eRat.A;
}
}
And this would give you the previous value on the same basis:
public static eRat Previous(this eRat target)
{
var nextValueQuery = Enum.GetValues(typeof(eRat)).Cast<eRat>().Reverse().SkipWhile(e => e != target).Skip(1);
if (nextValueQuery.Count() != 0)
{
return (eRat)nextValueQuery.First();
}
else
{
return eRat.D;
}
}
I'm using this, perfect for my.
//===================================================================================
// NEXT VALUE IN ENUM
// ex: E_CamModes eNew = kGlobalsVars.eGetNextValue< E_CamModes >( geCmMode );
public static T eGetNextValue< T >( T eIn ){
T[] aiAllValues = ( T[] ) Enum.GetValues( typeof( T ));
int iVal = System.Array.IndexOf( aiAllValues, eIn );
return aiAllValues[ ( iVal + 1 ) % aiAllValues.Length ];
}
There is a very simple solution (if you can change your integer values) that is specifically designed to work with numbers. The fact that your number is an enum, isn't a problem. It is still the integer (or whatever underlying number type you assign). Enum just adds the complexity of a cast requirement.
Assume your enum is defined like this:
public enum ItemStatus
{
New = 0,
Draft = 1,
Received = 2,
Review = 4,
Rejected = 8,
Approved = 16
}
ItemStatus myStatus = ItemStatus.Draft;
Use bitwise operations on the Enum. For Example:
myStatus = (ItemStatus)(((int)myStatus) << 1)
The result is of myStatus is: ItemStatus.Received.
You can also go backwards down the Enum by changing the bitwise operator from << to >>.
myStatus = (ItemStatus)(((int)myStatus) >> 1)
The result is of myStatus is: ItemStatus.New.
You should always add code to test for an "out of bounds" situation in both directions.
You can understand more about bitwise operations here: http://code.tutsplus.com/articles/understanding-bitwise-operators--active-11301
I would go with Sung Meister's answer but here is an alternative:
MyEnum initial = MyEnum.B, next;
for (int i = ((int) initial) + 1, i < int.MaxValue; i++)
{
if (Enum.IsDefined(typeof(MyEnum), (MyEnum) i))
{
next = (MyEnum) i;
break;
}
}
Note: many assumptions assumed :)
From comments I had many question like: "Why would you ever want to use enum in this way." Since so many of you asked, let me give you my use case and see if you agree then:
I have a fixed array of items int[n]. Depending on the situation I want to enumerate through this array differently. So i defined:
int[] Arr= {1,2,34,5,6,78,9,90,30};
enum eRat1 { A = 0, B=3, C=5, D=8 };
enum eRat2 { A, AA,AAA,B,BB,C,C,CC,D };
void walk(Type enumType)
{
foreach (Type t in Enum.GetValues(enumType))
{
write(t.ToString() + " = " + Arr[(int)t)];
}
}
and call walk(typeof(eRAt1)) or walk(typeof(eRAt2))
then i get required output
1) walk(typeof(eRAt1))
A = 1
B = 5
C = 78
D = 30
2) walk(typeof(eRAt2))
A = 1
AA = 2
AAA = 34
B = 5
BB = 6
C = 78
CC = 90
D = 30
This is very simplified. But i hope, this explains. There are some other advantages to this, as having enum.toString(). So basically i use enums as indexers.
So using the solution I can do something like this now.
In sequence eRat1 next value to B is C, but in eRat2 it is BB.
So depending on which sequence I am interested in, I can do e.next and depending on enumType I will either get C or BB. How would one achieve that with dictionaries?
I think this a rather elegant use of enums.
I'm using this here:
public MyEnum getNext() {
return this.ordinal() < MyEnum.values().length - 1 ?
MyEnum.values()[this.ordinal() + 1] :
MyEnum.values()[0];
}
LINQ solution that does not break on last element but continues at the default again:
var nextValue = Enum.GetValues(typeof(EnumT)).Cast<EnumT>().Concat(new[]{default(EnumT)}).SkipWhile(_ => _ != value).Skip(1).First();
I tried the first solution but it did not work for me. Below is my solution:
public object NextEnumItem(object currentEnumItem)
{
if (!currentEnumItem.GetType().IsEnum) throw new
ArgumentException(String.Format("Argument is not an Enum"));
Array Arr = Enum.GetValues(currentEnumItem.GetType());
int j = Array.IndexOf(Arr,currentEnumItem) + 1;
return (Arr.Length == j) ? currentEnumItem : Arr.GetValue(j);
}
public object PreviousEnumItem(object currentEnumItem)
{
if (!currentEnumItem.GetType().IsEnum)
throw new ArgumentException(String.Format("Argument is not an Enum"));
Array Arr = Enum.GetValues(currentEnumItem.GetType());
int j = Array.IndexOf(Arr, currentEnumItem) - 1;
return (j==-1) ? currentEnumItem : Arr.GetValue(j);
}
I did something similar with a different enum. It's for a game and the player has the chance to toggle colors.
public enum PlayerColor {
Red = 0, Green, Blue, Cyan, Yellow, Orange, Purple, Magenta
}
public PlayerColor GetNextFreeColor(PlayerColor oldColor) {
PlayerColor newColor = (PlayerColor)((int)(oldColor + 1) % 8);
return newColor;
}
This solution worked for me.
Based on best answer from Yahya Hussein here is edit of his code for Previous element in Enum
public static class Extensions
{
public static T Previous<T>(this T src) where T : struct
{
if (!typeof(T).IsEnum) throw new ArgumentException(String.Format("Argument {0} is not an Enum", typeof(T).FullName));
T[] Arr = (T[])Enum.GetValues(src.GetType());
int j = Array.IndexOf<T>(Arr, src) - 1;
return (j < 0) ? Arr[Array.Length - 1] : Arr[j];
}
}
enum Level
{
Easy,
Medium,
Expert
};
public static void Main()
{
var difficulty = Level.Easy;
var level = (int)difficulty;
Console.WriteLine(difficulty);
Console.WriteLine(level);
Console.WriteLine("promote level");
level++;
Console.WriteLine(level);
difficulty = (Level)level;
Console.WriteLine(difficulty);
}
You can add and remove integers to an enum to obtain the next value. The only problem is that integer operations on the enum will not check the validity of the enum itself, thus could set "invalid" values.
But you can combine the ++enum and the Enum.IsDefined() to obtain a simple way to get next and previous values of your enum. This would be inefficient in your case since the integer values are not continuous, but if you have continuous integers then it works nicely, and one can check when the ++enum is out of range. Check the next example.
public enum level
{
a = 0,
b = 1,
c = 2,
d = 3,
e = 4
}
private static void Main(string[] args)
{
var levelValue = level.a;
Console.WriteLine(levelValue);
++levelValue;
Console.WriteLine(levelValue);
++levelValue;
Console.WriteLine(levelValue);
++levelValue;
Console.WriteLine(levelValue);
++levelValue;
Console.WriteLine(levelValue);
++levelValue;
Console.WriteLine(Enum.IsDefined(typeof(Program.level), levelValue));
Console.WriteLine(levelValue);
--levelValue;
Console.WriteLine(levelValue);
--levelValue;
Console.WriteLine(levelValue);
--levelValue;
Console.WriteLine(levelValue);
--levelValue;
Console.WriteLine(levelValue);
--levelValue;
Console.WriteLine(Enum.IsDefined(typeof(Program.level), levelValue));
Console.WriteLine(levelValue);
--levelValue;
Console.WriteLine(Enum.IsDefined(typeof(Program.level), levelValue));
Console.WriteLine(levelValue);
}
The output for this would be:
a
b
c
d
e
False
5
e
d
c
b
True
a
False
-1

Categories