Related
I got an unordered list of int. Between 80 to 140 items, value of each item is between 0 and 175.
I'm generating a list of that list, about 5 to 10 millions of them.
I need to process, as fast as possible, all unique ordered sequence (excluding duplicate).
The way I'm doing it right now is creating a hash of all value of a list and inserting it into a hashset.
two hot spot while profiling is the ToArray() HOTSPOT1 and Array.Sort() HOTSPOT2
is there a better way of doing that task or a better alternative to fix the 2 hotspots? speed is important.
small demo, I tried to replicate as much as possible
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp1
{
class Example
{
//some other properties
public int Id { get; set; }
}
class Program
{
static void Main(string[] args)
{
var checkedUnlock = new HashSet<int>();
var data = FakeData();
foreach (List<Example> subList in data)
{
var hash = CalcHash(subList.Select(x => x.Id).ToArray()); // HOTPSOT1
var newHash = checkedUnlock.Add(hash);
if (newHash)
{
//do something
}
}
}
static int CalcHash(int[] value)
{
Array.Sort(value); // HOTPSOT2
int hash;
unchecked // https://stackoverflow.com/a/263416/40868
{
hash = (int)2166136261;
var i = value.Length;
while (i-- > 0)
hash = (hash * 16777619) ^ value[i];
}
return hash;
}
//don't look at this, this is just to fake data
static List<List<Example>> FakeData()
{
var data = new List<List<Example>>();
var jMax = 10; //normally between 80 and 140
var idMax = 25; //normally between 0 and 175
var rnd = new Random(42);
var ids = Enumerable.Range(0, idMax).ToArray();
for (int i = 0; i < 500000; ++i)
{
//force duplicate
if(i % 50000 == 0)
{
ids = Enumerable.Range(0, idMax).ToArray();
rnd = new Random(42);
}
for (int r = 0; r < idMax; ++r)
{
int randomIndex = rnd.Next(idMax);
int temp = ids[randomIndex];
ids[randomIndex] = ids[r];
ids[r] = temp;
}
var subList = new List<Example>();
data.Add(subList);
for (int j = 0; j < jMax; ++j)
{
subList.Add(new Example() { Id = ids[j] });
}
}
return data;
}
}
}
So you have an array that can contain up to 140 items, and all values are in the range 0 through 175. All values in the array are unique, and order doesn't matter. That is, the array [20, 90, 16] will be considered the same as [16, 20, 90].
Given that, you can represent a single array as a set of 175 bits. Better, you can create the set without having to sort the input array.
You represent a set in C# as a BitArray. To compute the hash code of your array, you create the set, and then you iterate over the set to get the hash code. It looks something like this:
private BitArray HashCalcSet = new BitArray(175);
int CalcHash(int[] a, int startIndex)
{
// construct the set
HashCalcSet.SetAll(false);
for (var i = startIndex; i < a.Length; ++i)
{
HashCalcSet[a[i]] = true;
}
// compute the hash
hash = (int)2166136261;
for (var i = 174; i >= 0; --i)
{
if (HashCalcSet[i])
{
hash = (hash * 16777619) ^ value[i];
}
}
return hash;
}
That eliminates the sorting as well as the ToArray. You have to loop over the BitArray a couple of times, but three passes over the BitArray is quite possibly faster than sorting.
One problem I see with your solution is in how you're using the HashSet. You have this code:
var hash = CalcHash(subList.Select(x => x.Id).ToArray()); // HOTPSOT1
var newHash = checkedUnlock.Add(hash);
if (newHash)
{
//do something
}
That code mistakenly assumes that if the hash codes for two arrays are equal, then the arrays are equal. You're generating a 32-bit hash code for a 175-bit quantity. There will definitely be hash collisions. You're going to end up saying that two of your arrays are identical, when they aren't.
If that is a concern to you, let me know and I can edit my answer to provide a solution.
Allowing for comparison
If you want the ability to compare items for equality, rather than just checking if their hash codes are the same, you need to create an object that has Equals and GetHashCode methods. You'll insert that object into your HashSet. The simplest of those objects would contain the BitArray I described above, and methods that operate on it. Something like:
class ArrayObject
{
private BitArray theBits;
private int hashCode;
public override bool Equals(object obj)
{
if (object == null || GetType() != obj.GetType())
{
return false;
}
ArrayObject other = (ArrayObject)obj;
// compare two BitArray objects
for (var i = 0; i < theBits.Length; ++i)
{
if (theBits[i] != other.theBits[i])
return false;
}
return true;
}
public override int GetHashCode()
{
return hashCode;
}
public ArrayObject(int hash, BitArray bits)
{
theBits = bits;
hashCode = hash;
}
}
The idea being that you construct the BitArray and the hash code in the method as described above (although you'll have to allocate a new BitArray for each call), and then create and return one of these ArrayObject instances.
Your HashSet becomes HashSet<ArrayObject>.
The above works, but it's a big of a memory hog. You could reduce the memory requirement by creating a class that contains just three long integers. Instead of using a BitArray, you manipulate the bits directly. You map the bits so that numbers 0 through 63 modify bits 0 through 63 in the first number. Numbers 64 through 127 correspond to bits 0 through 63 of the second number, etc. You don't have to save a separate hash code then, because it'd be easy to compute from the three longs, and equality comparison becomes a lot easier, too.
The class looks something like this. Understand, I haven't tested the code, but the idea should be sound.
class ArrayObject2
{
private long l1;
private long l2;
private long l3;
public ArrayObject2(int[] theArray)
{
for (int i = 0; i < theArray.Length; ++i)
{
var rem = theArray[i] % 63;
int bitVal = 1 << rem;
if (rem < 64) l1 |= bitVal;
else if (rem < 128) l2 |= bitVal;
else l3 |= bitVal;
}
}
public override bool Equals(object obj)
{
var other = obj as ArrayObject2;
if (other == null) return false;
return l1 == other.l1 && l2 == other.l2 && l3 == other.l3;
}
public override int GetHashCode()
{
// very simple, and not very good hash function.
return (int)l1;
}
}
As I commented in the code, the hash function there isn't great. It will work, but you can do better with a little research.
This approach has the advantage of using less memory than the BitArray or the Boolean array. It'll probably be slower than the array of bool. It might be faster than the BitArray code. But whatever the case, it'll keep you from making the mistaken assumption that identical hash codes equals identical arrays.
I think you can save some time by re-using one array of bigger size instead of allocating new array every time causing extra memory traffic and garbage collection.
That would require custom sorting implementation which knows that even though array can have 1000 items, for current run only first 80 items needs to be sorted (and same for hash). It looks quicksort operating on subrange of ids should work fine. Quick sample of idea (haven't tested in details)
int[] buffer = new int[1000];
foreach (List<Example> subList in data)
{
for (int i = 0; i < subList.Count; i++)
{
buffer[i] = subList[i].Id;
}
var hash = CalcHashEx(buffer, 0, subList.Count - 1);
var newHash = checkedUnlock.Add(hash);
if (newHash)
{
//do something
}
}
public static void QuickSort(int[] elements, int left, int right)
{
int i = left, j = right;
int pivot = elements[(left + right) / 2];
while (i <= j)
{
while (elements[i] < pivot)
{
i++;
}
while (elements[j] > pivot)
{
j--;
}
if (i <= j)
{
// Swap
int tmp = elements[i];
elements[i] = elements[j];
elements[j] = tmp;
i++;
j--;
}
}
if (left < j)
{
QuickSort(elements, left, j);
}
if (i < right)
{
QuickSort(elements, i, right);
}
}
static int CalcHashEx(int[] value, int startIndex, int endIndex)
{
QuickSort(value, startIndex, endIndex);
int hash;
unchecked // https://stackoverflow.com/a/263416/40868
{
hash = (int)2166136261;
var i = endIndex + 1;
while (i-- > 0)
hash = (hash * 16777619) ^ value[i];
}
return hash;
}
This version of CalcHash() will let you remove the .ToArray() and replaces the Array.Sort() with something different that can act on a sequence, rather than needing the entire set... so that's both hot spots.
static int CalcHash(IEnumerable<int> value)
{
value = value.OrderByDescending(i => i);
int hash;
unchecked // https://stackoverflow.com/a/263416/40868
{
hash = (int)2166136261;
foreach(var item in value)
{
hash = (hash * 16777619) ^ item;
}
}
return hash;
}
I'm not sure how OrderByDescending() will fare in comparison. I suspect it will be slower than Array.Sort(), but still be an over-all win because of eliminating ToArray()... but you'll need to run the profiler again to know for sure.
There may also be improvement you can get from eliminating or reducing branching, via .GroupBy(), and running the code on the .First() item in each group:
var groups = data.GroupBy(sub => CalcHash(sub.Select(x => x.Id)));
foreach(List<Example> subList in groups.Select(g => g.First()))
{
//do something
}
going to put this here since it make no sense to put it in a comment
so far what I have done is created an array of boolean and setting the index of the item to true when present and I replaced the CalcHash with;
unchecked
{
hash = (int)2166136261;
var i = theMaxLength;
while (i-- > 0)
if(testing[i]) //the array of boolean
{
hash = (hash * 16777619) ^ i;
testing[i] = false;
}
}
doing so I removed the ToArray() and the Array.Sort() completely, this solution is kind of built from the dlxeon/jim/joel answer
i dropped the runtime by about 20-25% which is great
I have a double[] array, i want to use it as key (not literally, but in the way that the key is matched when all the doubles in the double array need to be matched)
What is the fastest way to use the double[] array as key to dictionary?
Is it using
Dictionary<string, string> (convert double[] to a string)
or
anything else like converting it
Given that all key arrays will have the same length, either consider using a Tuple<,,, ... ,>, or use a structural equality comparer on the arrays.
With tuple:
var yourDidt = new Dictionary<Tuple<double, double, double>, string>();
yourDict.Add(Tuple.Create(3.14, 2.718, double.NaN), "da value");
string read = yourDict[Tuple.Create(3.14, 2.718, double.NaN)];
With (strongly typed version of) StructuralEqualityComparer:
class DoubleArrayStructuralEqualityComparer : EqualityComparer<double[]>
{
public override bool Equals(double[] x, double[] y)
{
return System.Collections.StructuralComparisons.StructuralEqualityComparer
.Equals(x, y);
}
public override int GetHashCode(double[] obj)
{
return System.Collections.StructuralComparisons.StructuralEqualityComparer
.GetHashCode(obj);
}
}
...
var yourDict = new Dictionary<double[], string>(
new DoubleArrayStructuralEqualityComparer());
yourDict.Add(new[] { 3.14, 2.718, double.NaN, }, "da value");
string read = yourDict[new[] { 3.14, 2.718, double.NaN, }];
Also consider the suggestion by Sergey Berezovskiy to create a custom class or (immutable!) struct to hold your set of doubles. In that way you can name your type and its members in a natural way that makes it more clear what you do. And your class/struct can easily be extended later on, if needed.
Thus all arrays have same length and each item in array have specific meaning, then create class which holds all items as properties with descriptive names. E.g. instead of double array with two items you can have class Point with properties X and Y. Then override Equals and GetHashCode of this class and use it as key (see What is the best algorithm for an overriding GetHashCode):
Dictionary<Point, string>
Benefits - instead of having array, you have data structure which makes its purpose clear. Instead of referencing items by indexes, you have nice named property names, which also make their purpose clear. And also speed - calculating hash code is fast. Compare:
double[] a = new [] { 12.5, 42 };
// getting first coordinate a[0];
Point a = new Point { X = 12.5, Y = 42 };
// getting first coordinate a.X
[Do not consider this a separate answer; this is an extension of #JeppeStigNielsen's answer]
I'd just like to point out that you make Jeppe's approach generic as follows:
public class StructuralEqualityComparer<T>: IEqualityComparer<T>
{
public bool Equals(T x, T y)
{
return StructuralComparisons.StructuralEqualityComparer.Equals(x, y);
}
public int GetHashCode(T obj)
{
return StructuralComparisons.StructuralEqualityComparer.GetHashCode(obj);
}
public static StructuralEqualityComparer<T> Default
{
get
{
StructuralEqualityComparer<T> comparer = _defaultComparer;
if (comparer == null)
{
comparer = new StructuralEqualityComparer<T>();
_defaultComparer = comparer;
}
return comparer;
}
}
private static StructuralEqualityComparer<T> _defaultComparer;
}
(From an original answer here: https://stackoverflow.com/a/5601068/106159)
Then you would declare the dictionary like this:
var yourDict = new Dictionary<double[], string>(new StructuralEqualityComparer<double[]>());
Note: It might be better to initialise _defaultComparer using Lazy<T>.
[EDIT]
It's possible that this might be faster; worth a try:
class DoubleArrayComparer: IEqualityComparer<double[]>
{
public bool Equals(double[] x, double[] y)
{
if (x == y)
return true;
if (x == null || y == null)
return false;
if (x.Length != y.Length)
return false;
for (int i = 0; i < x.Length; ++i)
if (x[i] != y[i])
return false;
return true;
}
public int GetHashCode(double[] data)
{
if (data == null)
return 0;
int result = 17;
foreach (var value in data)
result += result*23 + value.GetHashCode();
return result;
}
}
...
var yourDict = new Dictionary<double[], string>(new DoubleArrayComparer());
Ok this is what I found so far:
I input an entry (length 4 arrray) to the dictionary, and access it for 999999 times on my machine:
Dictionary<double[], string>(
new DoubleArrayStructuralEqualityComparer()); takes 1.75 seconds
Dictionary<Tuple<double...>,string> takes 0.85 seconds
The code below takes 0.1755285 seconds, which is the fastest now! (in line with the comment with Sergey.)
The fastest - The code of DoubleArrayComparer by Matthew Watson takes 0.15 seconds!
public class DoubleArray
{
private double[] d = null;
public DoubleArray(double[] d)
{
this.d = d;
}
public override bool Equals(object obj)
{
if (!(obj is DoubleArray)) return false;
DoubleArray dobj = (DoubleArray)obj;
if (dobj.d.Length != d.Length) return false;
for (int i = 0; i < d.Length; i++)
{
if (dobj.d[i] != d[i]) return false;
}
return true;
}
public override int GetHashCode()
{
unchecked // Overflow is fine, just wrap
{
int hash = 17;
for (int i = 0; i < d.Length;i++ )
{
hash = hash*23 + d[i].GetHashCode();
}
return hash;
}
}
}
I have a program I wrote some years back to find "good" binary operators for bytes; byte A is left multiplied by byte B to yield byte C. The operator is defined as 256x256 byte matrix. A stripped down version of the class implementation is below.
Equals() is true IFF all 65536 bytes in the array are the same.
CompareTo() compares the Linearity of the operator into a continuum of more linear (bad for cryto) to less linear (good for crypto).
So it is possible for two instances, A and B, that both of the following are true:
A.Equals(B) = false
(A.ComparesTo(B) == 0) = true
My question is less: Is this a good idea? I know the answer is No, but given the large computational cost of measuring linearity and the narrow nature of my problem this design works. Also code similar to:
if (localMinimumOperator < globalMinimumOperator)
{
localMinimumOperator = globalMinimumOperator;
}
is easier for me to read.
My question is: What are the consequences of this divergence among: ==, CompareTo()== 0, and Equals()? or alternately:
Is there list of which LINQ extensions methods describing which extension use which interface (IEquatable or IComparable)?
Something more concise than this MSDN article on Enumerable?
For example:
IEnumerable<BinaryOperation> distinct = orgList.Distinct();
calls Equals(BinaryOperator) as per: Enumerable.Distinct<TSource> Method as does Contains(). I understand that Sort() and OrderBy() use calls to CompareTo().
But what about FindFirst() and BinarySearch()?
My example class:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Jww05
{
public class BinaryOperation : IEquatable<BinaryOperation>, IComparable<BinaryOperation>
{
#region ClassMembers
public List<List<byte>> TruthTable
{
get
{
// I don't like giving out the underlying list if I help it
var retVal = new List<List<byte>>(OperatorDefintion);
return retVal;
}
}
// private data store for TruthTable
private List<List<byte>> OperatorDefintion { get; set; }
public BinaryOperation()
{
// initial state is the Identity operator
OperatorDefintion = new List<List<byte>>();
for (int i = 0; i < 256; i++)
{
var curRow = new List<byte>();
for (int j = 0; j < 256; j++)
{
curRow.Add((byte)(i + j));
}
OperatorDefintion.Add(curRow);
}
}
private long MeasureOperatorLinearity()
{
var diagonalOffsets = new byte[] { 255, 0, 1 };
/*
* Code that measures linearity in the original code used the Fast Walsh Hadamard Transform.
* That should go here, but it is removed because the FWHT is clutter for the purposes of this question.
*
* Since I needed a stub for this, I decided to exacerbate the differnece
* between CompareTo() == 0 and Equals()
* by returning an arbitrary int in lieu of the long CPU intensive Fast Walsh Hadamard Transform.
*
* If the matrices are identical on an element-by-element basis, then the Faux Linearity will be the the same.
* If the faux linearity (sum of terms on the main diagonal and corners) are the same, the underlying matrices could be different on an element-by-element basis.
*/
long fauxLinearityMeasure = 0;
for (var currRow = 0; currRow < OperatorDefintion.Count(); ++currRow)
{
fauxLinearityMeasure *= 5;
fauxLinearityMeasure = diagonalOffsets.Select(diagonalOffset => (byte)(currRow + diagonalOffset))
.Aggregate(fauxLinearityMeasure, (current, offestedIndex) => current + (OperatorDefintion[offestedIndex][currRow]));
}
return (int)fauxLinearityMeasure;
}
#endregion ClassMembers
#region ComparisonOperations
public int CompareTo(BinaryOperation other)
{
long otherLinearity = other.MeasureOperatorLinearity();
long thisLinearity = MeasureOperatorLinearity();
long linearityDiff = thisLinearity - otherLinearity;
// case the differnece of the linarity measures into {-1, 0, 1}
return (0 < linearityDiff) ? 1
: (0 > linearityDiff) ? -1
: 0;
}
public static bool operator >(BinaryOperation lhs, BinaryOperation rhs)
{
if (ReferenceEquals(null, lhs) ||
ReferenceEquals(null, rhs))
{
return false;
}
return (0 < lhs.CompareTo(rhs));
}
public static bool operator <(BinaryOperation lhs, BinaryOperation rhs)
{
if (ReferenceEquals(null, lhs) ||
ReferenceEquals(null, rhs))
{
return false;
}
return (0 > lhs.CompareTo(rhs));
}
public static bool operator <=(BinaryOperation lhs, BinaryOperation rhs)
{
if (ReferenceEquals(null, lhs) ||
ReferenceEquals(null, rhs))
{
return false;
}
// equals is cheap
if (lhs.Equals(rhs))
{
return true;
}
return (0 > lhs.CompareTo(rhs));
}
public static bool operator >=(BinaryOperation lhs, BinaryOperation rhs)
{
if (ReferenceEquals(null, lhs) ||
ReferenceEquals(null, rhs))
{
return false;
}
// equals is cheap
if (lhs.Equals(rhs))
{
return true;
}
return (0 < lhs.CompareTo(rhs));
}
#endregion ComparisonOperations
#region EqualityOperators
public bool Equals(BinaryOperation other)
{
if (ReferenceEquals(null, other))
{
return false;
}
var otherTruthTable = other.TruthTable;
var thisTruthTable = TruthTable;
var isEquals = true;
for (int currRow = 0; currRow < thisTruthTable.Count(); ++currRow)
{
isEquals = isEquals && thisTruthTable[currRow].SequenceEqual(otherTruthTable[currRow]);
}
return isEquals;
}
public override bool Equals(object obj)
{
return Equals(obj as BinaryOperation);
}
public override int GetHashCode()
{
return OperatorDefintion.SelectMany(currRow => currRow)
.Aggregate(1, (current, currByte) => current * 5 + currByte);
}
public static bool operator ==(BinaryOperation lhs, BinaryOperation rhs)
{
if (ReferenceEquals(null, lhs) ||
ReferenceEquals(null, rhs))
{
return false;
}
return (0 == lhs.CompareTo(rhs));
}
public static bool operator !=(BinaryOperation lhs, BinaryOperation rhs)
{
if (ReferenceEquals(null, lhs) ||
ReferenceEquals(null, rhs))
{
return false;
}
return (0 != lhs.CompareTo(rhs));
}
#endregion EqualityOperators
}
}
What are the consequences of this divergence among: ==, CompareTo()== 0, and Equals()?
Someone looking at your code in the future will truly hate you.
or alternately: Is there list of which linq extensions methods describing which extension use which interface (IEquitable or IComparable)?
I think that you've found most of it by yourself. A good rule of thumb is that usually there is nothing surprising in what interface is used by which LINQ function (no surprises is one of features of good design - unlike yours). For example: it's quite obvious that to sort elements it is necessary to know in which particular order should elements go, equality/inequality alone are not sufficient for this. BinarySearch also needs to know "which way to go" during search - if element is larger than current it re-curses into upper part of sorted array, if smaller it goes into lower. Again: obviously it needs IComparable. For Distinct Equals and GetHashCode suffice - sorting is not needed to determine a set of unique elements. And so on.
Hi say I have three ints: value1, value2 and value3.
How do I best determine if they are all the same?
I tried:
return value1 == value2 == value3
But this said:
Operator '==' cannot be applied to operands of type 'bool' and 'int'.
So I guess it compares the first two which returns a boolean which it tries to compare to the third.
I could go:
return value1 == value2 && value2 == value3;
But this seems to be getting untidy.
Anybody have a good suggestion?
The second seems just fine to me.
As the list gets longer, that could get unwieldy. In which case I'd write an extension method along the lines of AllSame.
bool AllSame(this IEnumerable<int> list)
{
bool first = true;
int comparand = 0;
foreach (int i in list) {
if (first) comparand = i;
else if (i != comparand) return false;
first = false;
}
return true;
}
or use the params keyword:
bool AllSame(params int[] list)
{
return (list as IEnumerable<int>).AllSame();
}
Then you can just write:
if (AllSame(value1, value2, value3, value4, value5)) ...
That seems fine to me. The only comment I have is that you should introduce an 'explaining variable' for the equation. Besides explaining the calculation, the return now provides a nice place for a breakpoint or a tracepoint when inspecting the result.
bool allThreeAreEqual = value1 == value2 && value2 == value3;
return allThreeAreEqual;
I modified my original answer to include a method that is more general purpose and that does not rely on LINQ or extension methods. I think it's safe to assume this method would be more performant based on the fact that it doesn't have to enumerate the entire list to determine uniqueness when there are values that are different early on in the list.
class Program
{
static void Main(string[] args)
{
int value1 = 1, value2 = 2, value3 = 1;
Console.WriteLine(AllAreEqual<int>(value1, value2, value3));
Console.Write("V2: 1 value ");
Console.WriteLine(AllAreEqual_V2<int>(1));
Console.Write("V2: no value ");
Console.WriteLine(AllAreEqual_V2<int>());
Console.Write("V2: 3 values, same ");
Console.WriteLine(AllAreEqual_V2<int>(1, 1, 1));
Console.Write("V2: 3 values, different ");
Console.WriteLine(AllAreEqual_V2<int>(1, 1, 2));
Console.Write("V2: 2 values, same ");
Console.WriteLine(AllAreEqual_V2<int>(1, 1));
Console.Write("V2: 2 values, different ");
Console.WriteLine(AllAreEqual_V2<int>(1, 2));
Console.ReadKey();
}
static bool AllAreEqual<T>(params T[] args)
{
return args.Distinct().ToArray().Length == 1;
}
static bool AllAreEqual_V2<T>(params T[] args)
{
if (args.Length == 0 || args.Length == 1)
{
return true;
}
if (args.Length == 2)
{
return args[0].Equals(args[1]);
}
T first = args[0];
for (int index = 1; index < args.Length; index++)
{
if (!first.Equals(args[index]))
{
return false;
}
}
return true;
}
}
If you are just looking for elegance (Considering your already have a solution that has nothing wrong with it ) , you could go with good'ol LINQ. This can handle three or more.
class Program
{
static void Main(string[] args)
{
List<int> mylist = new List<int>();
mylist.Add(1);
mylist.Add(1);
mylist.Add(1);
mylist.Add(1);
bool allElementsAreEqual = mylist.All( x => ( x == mylist.First() ));
}
}
You can do it like this also
bool AllSame(int a, int b, int c, int comparand) {
return board[a] == comparand && board[b] == comparand && board[c] == comparand;
}
int nOneInput = 5;
int nTwoInput = 5;
int nThreeInput = 5;
if ((nOneInput + nTwoInput + nThreeInput ) / 3 == nOneInput )
{
// all 3 sides are equal when...
// the sum of all 3 divided by 3 equals one of the values
}
Using LINQ it would be best to us Any(). Why Any() instead of All() is because All() will test the predicate on all the items of the collection while Any() will exit as soon as and item match the predicate.
Here i use a reverse check. I am looking for any item that will be different than the item "a". So as soon it find one different we know they are not all equals so it exit and return true. So it will only test item "b", "c" and "d".
// all values to compare
var a = 4;
var b = 4;
var c = 4;
var d = 8;
var e = 6;
var f = 4;
// return if any of the following is different and negate to get a true
var areSame = (!new[] { b, c, d, e, f}.Any(i => i != a));
If you override equals you can create generic extensions from this that is reusable and can work for multiple type as long as they implement IEqualityComparer<T>
This is what I would do
if((value1 == value2) && (value1 == value3) && (value2 == value3))
{
//Whatever you want here
}
The accepted answer works fine, but I needed to support different types too,
so this is the generic version
public static bool AllSame<T>(params T[] items)
{
var first = true;
T comparand = default;
foreach (var i in items)
{
if (first) comparand = i;
else if (!i.Equals(comparand)) return false;
first = false;
}
return true;
}
usage:
if (AllSame(true, false, true)) // false
if (AllSame(5, 5, 5)) // true
if (AllSame(record1 , record2, record3))
I want to check whether these variables have same values.
EXAMPLE:
int a = 5;
int b = 5;
int c = 5;
int d = 5;
int e = 5;
. . .
int k = 5;
if(a==b && b==c && c==d && d==e && .... && j==k)
{
//this is Complex way and not well understandable.
}
Any easy way to Compare all are same?
LIKE in below example
if(a==b==c==d==e.....j==k)
{
//Understandable but not work
}
how about something like this:
if (Array.TrueForAll<int>(new int[] {a, b, c, d, e, f, g, h, i, j, k },
val => (a == val))) {
// do something
}
With this many variables, would it make sense to move them into an array?
You could then test to see if they are all equal using Linq expressions like myarray.Distinct().Count() == 1; or perhaps myarray.All(r => r == 5);
You could create a var args method to do that:
bool intsEqual (params int[] ints) {
for (int i = 0; i < ints.Length - 1; i++) {
if (ints[i] != ints[i+1]) {
return False;
}
}
return True;
}
Then just call it with all your ints as parameters:
if (intsEqual(a, b, c, d, e, f, g, h, i, j, k)) {
doSomeStuff();
}
Just a thought, but if you can calculate the standard deviation of the entire list, and it is equal to zero, you would have your answer.
Here's an answer on the site that addresses this that may help with that: Standard deviation of generic list?
Interesting problem. Good luck with it.
I agree that the easiest way is to place them all into a list and then use the following to compare. This is in essence looping through and comparing to the first value, but this is a little cleaner.
var match = counts.All(x => x == counts[0])
How about
int common = a;
if (a==common && b==common && c==common && d==common && .... && k==common)
You could write a helper method like this:
public static bool AllEqual<T> (params T[] values) where T : IEquatable<T>
{
if (values.Length < 2) return true;
for (int i = 1; i < values.Length; i++)
if (!values[i].Equals (values[0])) return false;
return true;
}
This will be subtly different to the == operator in special cases, though:
AllEqual (double.NaN, double.NaN).Dump(); // True
(double.NaN == double.NaN).Dump(); // False
It doesn't work because a==b evaluates to a boolean which can't be compared to an integer, c. What you have seems to be the best way.
You might consider putting the values in an array and using a for() loop. It isn't really any simpler, but it might help if the number of values changed.
You could use a variable argument helper function to perform the comparison pretty easily.
static bool CompareLongList(params int[] args)
{
if (args.Length > 1)
{
int value = args[0];
for (int i = 1; i < args.Length; ++i)
{
if (value != args[i])
return false;
}
}
return true;
}
Then you would just use the function as follows
if(CompareLongList(a,b,c,d,e,f,j,h,i,j,k))
{
// True Code
}
I know it's an old question I came across but I was wondering what's wrong with:
if (a == (b & c & d & e & f & g & h & i & j & k))
{
}
Compare the same elements in array:
same = len(uniq([1,2,3,4])) == 1
Use Linq Query.
var greatestInt = new List() { a,b,c,d,e,f}.Max();
Bitwise and is a possible way to check multiple variables for same value.
Such a helper method could of course also check for equality instead of using the '&' operator. Helper method accepting a params array of variables seems to be the right method here. We could adjust this method to accept a generic argument also, but there are only a few data types which support boolean logical operators anyways in C# (and other languages).
Testing with a high value of Int32 to check validity of this:
void Main()
{
int a = 1234567891;
int b = 1234567891;
int c = 1234567891;
int d = 1234567891;
int e = 1234567891;
int f = 1234567891;
int g = 1234567891;
int h = 1234567891;
int i = 1234567891;
int j = 1234567891;
int k = 1234567891;
bool areAllSameValue = IntUtils.AreAllVariablesSameValue(a,b,c,d,e,f,g,h,i,j,k);
areAllSameValue.Dump(); //Linqpad method - dump this code into Linqpad to test
}
public class IntUtils
{
public static bool AreAllVariablesSameValue(params int[] values)
{
if (values == null || !values.Any())
{
return false;
}
int bitWiseAndValue = values[0];
foreach (var value in values)
{
bitWiseAndValue &= value;
}
return bitWiseAndValue == values[0];
}
}
This spots also if one of the values got a different sign (negative number).