Int as array representation - c#

I need an int array, from an int value.
The int value 123456 converts to int[] {1,2,3,4,5,6}.
Is there any better solution than this:
using System.Diagnostics;
namespace test
{
#if DEBUG
[DebuggerDisplay("{GetDebuggerDisplay()}")]
#endif
public class IntArray
{
#if DEBUG
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
#endif
private int _value;
#if DEBUG
[DebuggerBrowsableAttribute(DebuggerBrowsableState.Never)]
#endif
private int[] _valueArray;
public IntArray(int intValue)
{
Value = intValue;
}
public int Value
{
get { return _value; }
set
{
_value = value;
_valueArray = null;
_valueArray = CreateIntArray(value);
}
}
public int[] Array
{
get { return _valueArray; }
}
private string GetDebuggerDisplay()
{
return string.Format("Value = {0}", Value);
}
private static int[] CreateIntArray(int value)
{
string s = value.ToString();
var intArray = new int[s.Length];
for (int i = 0; i < s.Length; i++)
intArray[i] = int.Parse(s[i].ToString());
return intArray;
}
}
}
Any help and criticism would be appreciated.

You can do as following using Linq. This is only the making of the array from the int value.
var arrayOfInts = myint.ToString().Select(i => int.Parse(i.ToString())).ToArray();
EDIT :
This can also be made as a extension method on int if you want to use this often.
public static class IntExtensions
{
public static int[] ToArray(this int i)
{
return i.ToString().Select(c => int.Parse(c.ToString())).ToArray();
}
}
Then you can use this extension by doing this :
var myArray = 123456.ToArray();

You may convert to int to String, later you can use LINQ to Convert each character to integer and then return an array of integers using .ToArray()
int a = 123456;
string tempA = a.ToString();
int[] temp = tempA.Select(r => Convert.ToInt32(r.ToString())).ToArray();
EDIT:
As per Styxxy comment:
int a = 123456;
int[] array = new int[a.ToString().Length];
int i = array.Length - 1;
while (a > 0)
{
array[i--] = a % 10;
a = a / 10;
}

Another approach:
public static int[] GetInts(this int value)
{
if (value == 0)
return new int[] { 0 };
else
{
int val = value;
List<int> values = new List<int>();
while (Math.Abs(val) >= 1)
{
values.Add(Math.Abs(val % 10));
val = val / 10;
}
values.Reverse();
return values.ToArray();
}
}
and use it:
int value = 123456;
int[] values = value.GetInts();
Edit: improved to work with negative numbers and zero

var res = 123456.ToString().Select(c => Int32.Parse(c.ToString())).ToArray();

Another way using char.GetNumericValue:
int[] ints = 123456.ToString().Select(c => (int)char.GetNumericValue(c)).ToArray();
or without Linq:
var chars = 123456.ToString();
int[] ints = new int[chars.Length];
for (int i = 0; i < chars.Length; i++)
ints[i] = (int)char.GetNumericValue(chars[i]);

As said in the comments, it is better to use basic arithmetic operations, rather than converting to a string, looping through a string and parsing strings to integers.
Here is an example (I made an extension method for an integer):
static class IntegerExtensions
{
public static int[] ToCypherArray(this int value)
{
var cyphers = new List<int>();
do
{
cyphers.Add(value % 10);
value = value / 10;
} while (value != 0);
cyphers.Reverse();
return cyphers.ToArray();
}
}
class Program
{
static void Main(string[] args)
{
int myNumber = 123456789;
int[] cypherArray = myNumber.ToCypherArray();
Array.ForEach(cypherArray, (i) => Console.WriteLine(i));
Console.ReadLine();
}
}

Related

Why Can't I implement generic method in C#?

I am trying to implement a simple generic method in c# that can convert from an NI ComplexSingle and NI ComplexDouble which are structs to a Complex as defined in System.Numerics, which is also a struct. Both
ComplexSingle and ComplexDouble have properties Real and Imaginary defined here:
public double Real
{
get
{
return _privateBackingFieldForProperty_Real;
}
set
{
double privateBackingFieldForProperty_Real = _privateBackingFieldForProperty_Real;
_privateBackingFieldForProperty_Real = value;
}
}
public double Imaginary
{
get
{
return _privateBackingFieldForProperty_Imaginary;
}
set
{
double privateBackingFieldForProperty_Imaginary = _privateBackingFieldForProperty_Imaginary;
_privateBackingFieldForProperty_Imaginary = value;
}
}
All I want to do is make a single function that can take in either a ComplexSingle array or ComplexDouble array and convert either one into a Complex array. I was hoping to do that by using a generic method as below. However, I soon realized that the Real and Imaginary properties could not be found because the generic passed in doesn't know about them. Then, I thought maybe I could use an interface, which I defined below that has the properties that are found in the actual struct. Now I am getting an error below at:
Complex[] complexes = ComplexNItoComplex<ComplexDouble>(cd);
that
Code is below:
using NationalInstruments;
using System;
using System.Numerics;
namespace ComplexStuff
{
class ComplexMod
{
static void Main(string[] args)
{
Complex c1 = new Complex(4, 3);
Complex c2 = new Complex(5, 4);
Complex c3 = new Complex(6, 5);
ComplexDouble cd1 = new ComplexDouble(4, 3);
ComplexDouble cd2 = new ComplexDouble(4, 3);
ComplexDouble cd3 = new ComplexDouble(4, 3);
ComplexSingle cs1 = new ComplexSingle(7, 2);
ComplexSingle cs2 = new ComplexSingle(7, 2);
ComplexSingle cs3 = new ComplexSingle(7, 2);
ComplexDouble[] cd = new ComplexDouble[]{
cd1, cd2, cd3
};
Complex[] complexes = ComplexNItoComplex<ComplexDouble>(cd);
}
public interface IComplexNI
{
public double Real { get; set; }
public double Imaginary { get; set; }
}
static Complex[] ComplexNItoComplex<T>(IList<T> NIComplex) where T : IComplexNI
{
Complex[] c = new Complex[NIComplex.Count];
for (int i = 0; i < NIComplex.Count; i++)
{
c[i] = new Complex(NIComplex[i].Real, NIComplex[i].Imaginary);
}
return c;
}
}
}
Complex Double:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.Serialization;
using System.Security;
using NationalInstruments.Internal;
using NationalInstruments.Restricted;
namespace NationalInstruments
{
[Serializable]
[DebuggerDisplay("\\{{Real} + {Imaginary}i}")]
[TypeConverter(typeof(ComplexDoubleConverter))]
public struct ComplexDouble : IFormattable, ISerializable, IEquatable<ComplexDouble>
{
private const string RealKey = "Real";
private const string ImaginaryKey = "Imaginary";
private double _privateBackingFieldForProperty_Real;
private double _privateBackingFieldForProperty_Imaginary;
public double Magnitude => Math.Sqrt(Real * Real + Imaginary * Imaginary);
public double Phase => Math.Atan2(Imaginary, Real);
public static ComplexDouble Zero => new ComplexDouble(0.0, 0.0);
public ComplexDouble ComplexConjugate => new ComplexDouble(Real, 0.0 - Imaginary);
public double Real
{
get
{
return _privateBackingFieldForProperty_Real;
}
set
{
double privateBackingFieldForProperty_Real = _privateBackingFieldForProperty_Real;
_privateBackingFieldForProperty_Real = value;
}
}
public double Imaginary
{
get
{
return _privateBackingFieldForProperty_Imaginary;
}
set
{
double privateBackingFieldForProperty_Imaginary = _privateBackingFieldForProperty_Imaginary;
_privateBackingFieldForProperty_Imaginary = value;
}
}
public ComplexDouble(double real, double imaginary)
{
this = default(ComplexDouble);
Real = real;
Imaginary = imaginary;
}
public static ComplexDouble FromPolar(double magnitude, double phase)
{
return new ComplexDouble(magnitude * Math.Cos(phase), magnitude * Math.Sin(phase));
}
public static ComplexDouble FromDouble(double real)
{
return new ComplexDouble(real, 0.0);
}
public static explicit operator ComplexDouble(double real)
{
return FromDouble(real);
}
public override string ToString()
{
return ToString(null, null);
}
public string ToString(string format)
{
return ToString(format, null);
}
public string ToString(IFormatProvider formatProvider)
{
return ToString(null, formatProvider);
}
public string ToString(string format, IFormatProvider formatProvider)
{
string text = Real.ToString(format, formatProvider);
string text2 = Math.Abs(Imaginary).ToString(format, formatProvider);
NumberFormatInfo numberFormat = ComplexParser.GetNumberFormat(formatProvider);
string text3 = (Real.IsNegativeZero() ? numberFormat.NegativeSign : null);
string text4 = ((Imaginary < 0.0 || Imaginary.IsNegativeZero()) ? numberFormat.NegativeSign : numberFormat.PositiveSign);
return string.Format(CultureInfo.InvariantCulture, "{0}{1} {2} {3}i", text3, text, text4, text2);
}
public static ComplexDouble Parse(string input)
{
return Parse(input, null);
}
public static ComplexDouble Parse(string input, IFormatProvider provider)
{
if (input == null)
{
throw ExceptionBuilderBase.ArgumentNull("input");
}
if (!ComplexParser.AttemptParse(input, NumberStyles.Float | NumberStyles.AllowThousands, provider, ComplexParser.TryParseDouble, out var real, out var imaginary))
{
throw ExceptionBuilder.InvalidComplexDoubleFormat(input);
}
return new ComplexDouble(real, imaginary);
}
public static bool TryParse(string input, out ComplexDouble result)
{
return TryParse(input, null, out result);
}
public static bool TryParse(string input, IFormatProvider provider, out ComplexDouble result)
{
double real;
double imaginary;
bool result2 = ComplexParser.AttemptParse(input, NumberStyles.Float | NumberStyles.AllowThousands, provider, ComplexParser.TryParseDouble, out real, out imaginary);
result = new ComplexDouble(real, imaginary);
return result2;
}
public static ComplexDouble[] ComposeArray(double[] realData, double[] imaginaryData)
{
if (realData == null)
{
throw ExceptionBuilderBase.ArgumentNull("realData");
}
if (imaginaryData == null)
{
throw ExceptionBuilderBase.ArgumentNull("imaginaryData");
}
int num = realData.Length;
if (num != imaginaryData.Length)
{
throw ExceptionBuilder.ArrayLengthsNotEqual("imaginaryData");
}
ComplexDouble[] array = new ComplexDouble[num];
for (int i = 0; i < num; i++)
{
array[i] = new ComplexDouble(realData[i], imaginaryData[i]);
}
return array;
}
public static ComplexDouble[] ComposeArray(double[] realData, double[] imaginaryData, int startIndex, int length)
{
if (realData == null)
{
throw ExceptionBuilderBase.ArgumentNull("realData");
}
if (imaginaryData == null)
{
throw ExceptionBuilderBase.ArgumentNull("imaginaryData");
}
int num = realData.Length;
if (num != imaginaryData.Length)
{
throw ExceptionBuilder.ArrayLengthsNotEqual("imaginaryData");
}
if (startIndex < realData.GetLowerBound(0) || startIndex >= num)
{
throw ExceptionBuilderBase.ArgumentOutOfRange("startIndex");
}
if (length < 0 || startIndex + length > num)
{
throw ExceptionBuilderBase.ArgumentOutOfRange("length");
}
ComplexDouble[] array = new ComplexDouble[length];
int num2 = startIndex;
int num3 = 0;
while (num2 < startIndex + length)
{
array[num3] = new ComplexDouble(realData[num2], imaginaryData[num2]);
num2++;
num3++;
}
return array;
}
public static ComplexDouble[] ComposeArrayPolar(double[] magnitudes, double[] phases)
{
if (magnitudes == null)
{
throw ExceptionBuilderBase.ArgumentNull("magnitudes");
}
if (phases == null)
{
throw ExceptionBuilderBase.ArgumentNull("phases");
}
int num = magnitudes.Length;
if (num != phases.Length)
{
throw ExceptionBuilder.ArrayLengthsNotEqual("phases");
}
ComplexDouble[] array = new ComplexDouble[num];
for (int i = 0; i < num; i++)
{
array[i] = FromPolar(magnitudes[i], phases[i]);
}
return array;
}
public static ComplexDouble[] ComposeArrayPolar(double[] magnitudes, double[] phases, int startIndex, int length)
{
if (magnitudes == null)
{
throw ExceptionBuilderBase.ArgumentNull("magnitudes");
}
if (phases == null)
{
throw ExceptionBuilderBase.ArgumentNull("phases");
}
int num = magnitudes.Length;
if (num != phases.Length)
{
throw ExceptionBuilder.ArrayLengthsNotEqual("phases");
}
if (startIndex < magnitudes.GetLowerBound(0) || startIndex >= num)
{
throw ExceptionBuilderBase.ArgumentOutOfRange("startIndex");
}
if (length < 0 || startIndex + length > num)
{
throw ExceptionBuilderBase.ArgumentOutOfRange("length");
}
}
}
I know that the error only occurs if I have the real and imaginary properties in IComplexNI. I'm thinking I don't quite understand interfaces fully, since I was thinking that since I have Real and Complex defined in the interface, then the code would know to look for them when looking in the generic type. I guess that's wrong, though. I was guessing that you could reference the properties of objects or structs somehow in generic methods, but it sounds more complicated than what I was hoping..?
You can't write a single method to convert both types. Both types have a Real and an Imaginary property each, but the types of these properties are different.
The ComplexDouble type has Real and Imaginary properties of type double.
The ComplexSingle type has Real and Imaginary properties of type float.
The easiest solution is to use method overloading: You can have two methods with the same name and different parameter types. The compiler will then choose the correct method automatically based on the type of argument you pass to them:
static Complex[] ComplexNItoComplex(IEnumerable<ComplexDouble> NIComplex)
{
return (from c in NIComplex
select new Complex(c.Real, c.Imaginary))
.ToArray();
}
static Complex[] ComplexNItoComplex(IEnumerable<ComplexSingle> NIComplex)
{
return (from c in NIComplex
select new Complex(c.Real, c.Imaginary))
.ToArray();
}
Sample usage:
ComplexDouble cd1 = new ComplexDouble(4, 3);
ComplexDouble cd2 = new ComplexDouble(4, 3);
ComplexDouble cd3 = new ComplexDouble(4, 3);
ComplexSingle cs1 = new ComplexSingle(7, 2);
ComplexSingle cs2 = new ComplexSingle(7, 2);
ComplexSingle cs3 = new ComplexSingle(7, 2);
ComplexDouble[] cd = new ComplexDouble[]{
cd1, cd2, cd3
};
ComplexSingle[] cs = new ComplexSingle[]{
cs1, cs2, cs3
};
Complex[] complexes1 = ComplexNItoComplex(cd);
Complex[] complexes2 = ComplexNItoComplex(cs);

Sorting chapter stuff like 14.1.2.3 and 14.10.1.2.3.4

I've got various chapters with different depths.
so there are 14.1 and 14.4.2 and 14.7.8.8.2 and so on.
Alphanumerical sorted the 14.10 will appear before 14.2. That's bad. It should come after 14.9.
Is there an easy way to sort theese, without adding leading zeros? f.e. with linq?
public class NumberedSectionComparer : IComparer<string>
{
private int Compare(string[] x, string[]y)
{
if(x.Length > y.Length)
return -Compare(y, x);//saves needing separate logic.
for(int i = 0; i != x.Length; ++i)
{
int cmp = int.Parse(x[i]).CompareTo(int.Parse(y[i]));
if(cmp != 0)
return cmp;
}
return x.Length == y.Length ? 0 : -1;
}
public int Compare(string x, string y)
{
if(ReferenceEquals(x, y))//short-cut
return 0;
if(x == null)
return -1;
if(y == null)
return 1;
try
{
return Compare(x.Split('.'), y.Split('.'));
}
catch(FormatException)
{
throw new ArgumentException();
}
}
}
I did this right now, need some tests:
using System;
using System.Collections.Generic;
using System.Linq;
namespace TestesConsole
{
class Program
{
static void Main(string[] args)
{
string[] vers = new[]
{
"14.10",
"14.9",
"14.10.1",
};
var ordered = vers.OrderBy(x => x, new VersionComparer()).ToList();
}
}
public class VersionComparer : IComparer<string>
{
public int Compare(string x, string y)
{
string[] xs = x.Split('.');
string[] ys = y.Split('.');
int maxLoop = Math.Min(xs.Length, ys.Length);
for (int i = 0; i < maxLoop; i++)
{
if(int.Parse(xs[i]) > int.Parse(ys[i]))
{
return 1;
}
else if(int.Parse(xs[i]) < int.Parse(ys[i]))
{
return -1;
}
}
if(xs.Length > ys.Length)
{
return 1;
}
else if(xs.Length < ys.Length)
{
return -1;
}
return 0;
}
}
}
var headers = new List<string> {"14.1.2.3", "14.1", "14.9", "14.2.1", "14.4.2", "14.10.1.2.3.4", "14.7.8.8.2"};
headers.Sort(new MySorter());
class MySorter : IComparer<string>
{
public int Compare(string x, string y)
{
IList<string> a = x.Split('.');
IList<string> b = y.Split('.');
int numToCompare = (a.Count < b.Count) ? a.Count : b.Count;
for (int i = 0; i < numToCompare; i++)
{
if (a[i].Equals(b[i]))
continue;
int numa = Convert.ToInt32(a[i]);
int numb = Convert.ToInt32(b[i]);
return numa.CompareTo(numb);
}
return a.Count.CompareTo(b.Count);
}
}
Using IComparer hast the big disadvantage of repeating the rather expensive calculation very often, so I thought precalculating an order criterium would be a good idea:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ChapterSort
{
class Program
{
static void Main(string[] args)
{
String[] chapters=new String[] {"14.1","14.4.2","14.7.8.8.2","14.10","14.2","14.9","14.10.1.2.3.4","14.1.2.3" };
IEnumerable<String> newchapters=chapters.OrderBy(x => new ChapterNumerizer(x,256,8).NumericValue);
foreach (String s in newchapters) Console.WriteLine(s);
}
}
public class ChapterNumerizer
{
private long numval;
public long NumericValue {get{return numval;}}
public ChapterNumerizer (string chapter,int n, int m)
{
string[] c = chapter.Split('.');
numval=0;
int j=0;
foreach (String cc in c)
{
numval=n*numval+int.Parse(cc);
j++;
}
while (j<m)
{
numval*=n;
j++;
}
}
}
}
This solution is more general.
public class SequenceComparer<T> : IComparer<IEnumerable<T>> where T : IComparable<T>
{
public int Compare(IEnumerable<T> x, IEnumerable<T> y)
{
IEnumerator<T> enx = x.GetEnumerator();
IEnumerator<T> eny = y.GetEnumerator();
do
{
bool endx = enx.MoveNext();
bool endy = eny.MoveNext();
if (!endx && !endy)
return 0;
if (!endx)
return -1;
if (!endy)
return 1;
var comp = enx.Current.CompareTo(eny.Current);
if(comp != 0)
return comp;
} while (true);
}
}
Then use:
var sv = vers.Select(v => new { Key = v, Split = v.Split('.').Select(Int32.Parse) });
var ordered = sv.OrderBy(x => x.Split, new SequenceComparer<int>()).Select(x => x.Key);
As a small LINQ one-liner:
List<string> chapters= new List<string>()
{
"14.1",
"14.4.2",
"14.7.8.8.2",
"14.10",
"14.2"
};
chapters.OrderBy(c => Regex.Replace(c, "[0-9]+", match => match.Value.PadLeft(10, '0')));
Independent of levels but surely not the best performance...
Credits are going to https://stackoverflow.com/a/5093939/226278

How to create dynamic incrementing variable using “for” loop in C#

How to create dynamic incrementing variable using "for" loop in C#? like this:
track_1, track_2, track_3, track_4. so on.
You can't create dynamically-named variables. All you can do - it to create some collection or array, and operate with it.
I think the best class for you is generic List<>:
List<String> listWithDynamic = new List<String>();
for (int i = 1; i < limit; i +=1)
{
listWithDynamic.Add(string.Format("track_{0}", i));
...
}
Assuming you want strings:
for (int i = 1; i < limit; i +=1)
{
string track = string.Format("track_{0}", i);
...
}
But when you already have variables called track_1, track_2, track_3, track_4 you will need an array or List:
var tracks = new TrackType[] { track_1, track_2, track_3, track_4 } ;
for (int i = 0; i < tracks.length; i++)
{
var track = tracks[i]; // tracks[0] == track_1
...
}
Obvious Solution
for (var i = 0; i < 10; i++)
{
var track = string.Format("track_{0}", i);
}
Linq-Based Solution
foreach (var track in Enumerable.Range(0, 100).Select(x => string.Format("track_{0}", x)))
{
}
Operator-Based Solution This is somewhat hacky, but fun none-the-less.
for (var i = new Frob(0, "track_{0}"); i < 100; i++)
{
Console.WriteLine(i.ValueDescription);
}
struct Frob
{
public int Value { get; private set; }
public string ValueDescription { get; private set; }
private string _format;
public Frob(int value, string format)
: this()
{
Value = value;
ValueDescription = string.Format(format, value);
_format = format;
}
public static Frob operator ++(Frob value)
{
return new Frob(value.Value + 1, value._format);
}
public static Frob operator --(Frob value)
{
return new Frob(value.Value - 1, value._format);
}
public static implicit operator int(Frob value)
{
return value.Value;
}
public static implicit operator string(Frob value)
{
return value.ValueDescription;
}
public override bool Equals(object obj)
{
if (obj is Frob)
{
return ((Frob)obj).Value == Value;
}
else if (obj is string)
{
return ((string)obj) == ValueDescription;
}
else if (obj is int)
{
return ((int)obj) == Value;
}
else
{
return base.Equals(obj);
}
}
public override int GetHashCode()
{
return Value;
}
public override string ToString()
{
return ValueDescription;
}
}
don't know if I get your question, but I will try:
for(var i = 1; i < yourExclusiveUpperbound; i++)
{
var track = String.Format("$track_{0}", i);
// use track
}
or with some LINQ-Magic:
foreach(var track in Enumerate.Range(1, count)
.Select(i => String.Format("$track_{0}", i)))
{
// use track
}
Do as follow:
for (int i = 0; i < lenght; i ++)
{
any work do in loop
}
No, we can't create dynamically named variables in a loop. But, there are other elegant ways to address the problem instead of creating dynamically named variables.
One could be, create an array or list before the loop and store values in array / list items in the loop. You can access the array / list later anywhere in your code. If you know which variable you want to use (track_1, track_2, ...), you can simply access it from the array / list (tracks[1], tracks[2], ...).
List<String> tracks = new List<String>();
for (int i = 1; i < limit; i++)
{
Track track = new Track();
tracks.Add(track);
...
}

C# hashcode for array of ints

I have a class that internally is just an array of integers. Once constructed the array never changes. I'd like to pre-compute a good hashcode so that this class can be very efficiently used as a key in a Dictionary. The length of the array is less than about 30 items, and the integers are between -1000 and 1000 in general.
Not very clever, but sufficient for most practical purposes:
EDIT: changed due to comment of Henk Holterman, thanks for that.
int hc = array.Length;
foreach (int val in array)
{
hc = unchecked(hc * 314159 + val);
}
If you need something more sophisticated, look here.
For an array of values generally between -1000 and 1000, I would probably use something like this:
static int GetHashCode(int[] values)
{
int result = 0;
int shift = 0;
for (int i = 0; i < values.Length; i++)
{
shift = (shift + 11) % 21;
result ^= (values[i]+1024) << shift;
}
return result;
}
You may use CRC32 checksum. Here is the code:
[CLSCompliant(false)]
public class Crc32 {
uint[] table = new uint[256];
uint[] Table { get { return table; } }
public Crc32() {
MakeCrcTable();
}
void MakeCrcTable() {
for (uint n = 0; n < 256; n++) {
uint value = n;
for (int i = 0; i < 8; i++) {
if ((value & 1) != 0)
value = 0xedb88320 ^ (value >> 1);
else
value = value >> 1;
}
Table[n] = value;
}
}
public uint UpdateCrc(uint crc, byte[] buffer, int length) {
uint result = crc;
for (int n = 0; n < length; n++) {
result = Table[(result ^ buffer[n]) & 0xff] ^ (result >> 8);
}
return result;
}
public uint Calculate(Stream stream) {
long pos = stream.Position;
const int size = 0x32000;
byte[] buf = new byte[size];
int bytes = 0;
uint result = 0xffffffff;
do {
bytes = stream.Read(buf, 0, size);
result = UpdateCrc(result, buf, bytes);
}
while (bytes == size);
stream.Position = pos;
return ~result;
}
}
I think choosing a good hash-algorithm would have to be based on the distribution (in a probability sense) of the integer values.
Have a look at Wikipedia for a list of algorithms
Any CRC (or even XOR) should be ok.
You could take a different approach and use a recursive dictionary for each value in your int array. This way you can leave .net to do primitive type hashing.
internal class DictionaryEntry<TKey, TValue>
{
public Dictionary<TKey, DictionaryEntry<TKey, TValue>> Children { get; private set; }
public TValue Value { get; private set; }
public bool HasValue { get; private set; }
public void SetValue(TValue value)
{
Value = value;
HasValue = true;
}
public DictionaryEntry()
{
Children = new Dictionary<TKey, DictionaryEntry<TKey, TValue>>();
}
}
internal class KeyStackDictionary<TKey, TValue>
{
// Helper dictionary to work with a stack of keys
// Usage:
// var dict = new KeyStackDictionary<int, string>();
// int[] keyStack = new int[] {23, 43, 54};
// dict.SetValue(keyStack, "foo");
// string value;
// if (dict.GetValue(keyStack, out value))
// {
// }
private DictionaryEntry<TKey, TValue> _dict;
public KeyStackDictionary()
{
_dict = new DictionaryEntry<TKey, TValue>();
}
public void SetValue(TKey[] keyStack, TValue value)
{
DictionaryEntry<TKey, TValue> dict = _dict;
for (int i = 0; i < keyStack.Length; i++)
{
TKey key = keyStack[i];
if (dict.Children.ContainsKey(key))
{
dict = dict.Children[key];
}
else
{
var child = new DictionaryEntry<TKey, TValue>();
dict.Children.Add(key, child);
dict = child;
}
if (i == keyStack.Length - 1)
{
dict.SetValue(value);
}
}
}
// returns false if the value is not found using the key stack
public bool GetValue(TKey[] keyStack, out TValue value)
{
DictionaryEntry<TKey, TValue> dict = _dict;
for (int i = 0; i < keyStack.Length; i++)
{
TKey key = keyStack[i];
if (dict.Children.ContainsKey(key))
{
dict = dict.Children[key];
}
else
{
break;
}
if (i == keyStack.Length - 1 && dict.HasValue)
{
value = dict.Value;
return true;
}
}
value = default(TValue);
return false;
}
}
You can use Linq methods too:
var array = new int[10];
var hashCode = array.Aggregate(0, (a, v) =>
HashCode.Combine(a, v.GetHashCode()));
I'm using this here
var arrayHash = string.Join(string.Empty, array).GetHashCode();
If a element changed in the array, you will get a new hash.
I would recommend:
HashCode.Combine(array)
For .NET Core 2.1 / .NET Standard 2.1 / .NET 5 and later.

C# Extend array type to overload operators

I'd like to create my own class extending array of ints. Is that possible? What I need is array of ints that can be added by "+" operator to another array (each element added to each), and compared by "==", so it could (hopefully) be used as a key in dictionary.
The thing is I don't want to implement whole IList interface to my new class, but only add those two operators to existing array class.
I'm trying to do something like this:
class MyArray : Array<int>
But it's not working that way obviously ;).
Sorry if I'm unclear but I'm searching solution for hours now...
UPDATE:
I tried something like this:
class Zmienne : IEquatable<Zmienne>
{
public int[] x;
public Zmienne(int ilosc)
{
x = new int[ilosc];
}
public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
{
return false;
}
return base.Equals((Zmienne)obj);
}
public bool Equals(Zmienne drugie)
{
if (x.Length != drugie.x.Length)
return false;
else
{
for (int i = 0; i < x.Length; i++)
{
if (x[i] != drugie.x[i])
return false;
}
}
return true;
}
public override int GetHashCode()
{
int hash = x[0].GetHashCode();
for (int i = 1; i < x.Length; i++)
hash = hash ^ x[i].GetHashCode();
return hash;
}
}
Then use it like this:
Zmienne tab1 = new Zmienne(2);
Zmienne tab2 = new Zmienne(2);
tab1.x[0] = 1;
tab1.x[1] = 1;
tab2.x[0] = 1;
tab2.x[1] = 1;
if (tab1 == tab2)
Console.WriteLine("Works!");
And no effect. I'm not good with interfaces and overriding methods unfortunately :(. As for reason I'm trying to do it. I have some equations like:
x1 + x2 = 0.45
x1 + x4 = 0.2
x2 + x4 = 0.11
There are a lot more of them, and I need to for example add first equation to second and search all others to find out if there is any that matches the combination of x'es resulting in that adding.
Maybe I'm going in totally wrong direction?
For a single type, it is pretty easy to encapsulate, as below. Note that as a key you want to make it immutable too. If you want to use generics, it gets harder (ask for more info):
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
static class Program {
static void Main() {
MyVector x = new MyVector(1, 2, 3), y = new MyVector(1, 2, 3),
z = new MyVector(4,5,6);
Console.WriteLine(x == y); // true
Console.WriteLine(x == z); // false
Console.WriteLine(object.Equals(x, y)); // true
Console.WriteLine(object.Equals(x, z)); // false
var comparer = EqualityComparer<MyVector>.Default;
Console.WriteLine(comparer.GetHashCode(x)); // should match y
Console.WriteLine(comparer.GetHashCode(y)); // should match x
Console.WriteLine(comparer.GetHashCode(z)); // *probably* different
Console.WriteLine(comparer.Equals(x,y)); // true
Console.WriteLine(comparer.Equals(x,z)); // false
MyVector sum = x + z;
Console.WriteLine(sum);
}
}
public sealed class MyVector : IEquatable<MyVector>, IEnumerable<int> {
private readonly int[] data;
public int this[int index] {
get { return data[index]; }
}
public MyVector(params int[] data) {
if (data == null) throw new ArgumentNullException("data");
this.data = (int[])data.Clone();
}
private int? hash;
public override int GetHashCode() {
if (hash == null) {
int result = 13;
for (int i = 0; i < data.Length; i++) {
result = (result * 7) + data[i];
}
hash = result;
}
return hash.GetValueOrDefault();
}
public int Length { get { return data.Length; } }
public IEnumerator<int> GetEnumerator() {
for (int i = 0; i < data.Length; i++) {
yield return data[i];
}
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
public override bool Equals(object obj)
{
return this == (obj as MyVector);
}
public bool Equals(MyVector obj) {
return this == obj;
}
public override string ToString() {
StringBuilder sb = new StringBuilder("[");
if (data.Length > 0) sb.Append(data[0]);
for (int i = 1; i < data.Length; i++) {
sb.Append(',').Append(data[i]);
}
sb.Append(']');
return sb.ToString();
}
public static bool operator ==(MyVector x, MyVector y) {
if(ReferenceEquals(x,y)) return true;
if(ReferenceEquals(x,null) || ReferenceEquals(y,null)) return false;
if (x.hash.HasValue && y.hash.HasValue && // exploit known different hash
x.hash.GetValueOrDefault() != y.hash.GetValueOrDefault()) return false;
int[] xdata = x.data, ydata = y.data;
if(xdata.Length != ydata.Length) return false;
for(int i = 0 ; i < xdata.Length ; i++) {
if(xdata[i] != ydata[i]) return false;
}
return true;
}
public static bool operator != (MyVector x, MyVector y) {
return !(x==y);
}
public static MyVector operator +(MyVector x, MyVector y) {
if(x==null || y == null) throw new ArgumentNullException();
int[] xdata = x.data, ydata = y.data;
if(xdata.Length != ydata.Length) throw new InvalidOperationException("Length mismatch");
int[] result = new int[xdata.Length];
for(int i = 0 ; i < xdata.Length ; i++) {
result[i] = xdata[i] + ydata[i];
}
return new MyVector(result);
}
}
Its not permitted to extend the array class, see the reference: http://msdn.microsoft.com/en-us/library/system.array.aspx
You could either implement IList (which has the basic methods), or encapsulate an Array in your class and provide conversion operators.
Please let me know if you need more detail.
Can you not just use the List class? This already does what you want via the AddRange method.
implement the ienumerable interface

Categories

Resources