3

I would like to compare 2 equations, lets say 2*2 and 2+2 to a single answer, 4, using Visual Studio 2015, e.g.

if (4 == (2*2 && 2+2)) {...}

but it returns an error, "Operator '&&' cannot be applied to operands of type 'int' and 'int'". The only other way I could think of writing the code is:

if (4 == 2*2 && 4 == 2+2) {...}

which would work, but gets very repetitive when a lot of values are to be compared. Is there a easier way to achieve this?

Hamid Pourjam
  • 20,441
  • 9
  • 58
  • 74
Rikus Honey
  • 534
  • 1
  • 3
  • 17
  • No, there isn’t. Why? What is your use case? – poke Nov 16 '15 at 18:06
  • Short answer: no. Long answer: there are ways in which you could trade performance for some syntactic sugar, but it is really not worth it. – odyss-jii Nov 16 '15 at 18:06
  • 1
    Having a more descriptive context of your "lot of values" being compared, can you show more of your samples of comparisons? How many values ARE being compared, compared to what... fixed values, other variables? – DRapp Nov 16 '15 at 18:07
  • you're comparing (value) types; `Object.Equals(int, int)` may **not** work.. but you could just do anonymous object type check `Object.Equals(new { value = 2*2 }, new { value = 2+2 })` – Brett Caswell Nov 16 '15 at 18:08

6 Answers6

11
var results = new[]{ 2 + 2, 2 * 2, ... };
if (results.All(r => r == 4)) {
    ...
}

This gathers the results of all operations in the collection results, and uses the extension method All to verify that the specified predicate holds for all values; allowing to write the predicate only once.

Asik
  • 21,506
  • 6
  • 72
  • 131
  • Please an explanation of why this would solve the OP's problem. Help others to understand. – APC Nov 26 '15 at 08:00
5

You could write a function:

public static bool AllEqual<T>(T expectedResult, params T[] calculations)
    where T : IEquatable<T>
{
    return calculations.All(x => x.Equals(expectedResult));
}

For example:

if (AllEqual(4, 2 + 2, 2 * 2, 1 + 1 + 1 + 1)) {
    // true
}

if (AllEqual(4, 2 + 2, 2 * 3)) {
    // not true
}

This even works for other types, e.g.

if (AllEqual("foo", "f" + "o" + "o", "fooo".Substring(0, 3))) {
    // true
}
poke
  • 369,085
  • 72
  • 557
  • 602
  • I apologize, I meant to just take away my up vote until I confirmed something: namely does int (a struct value type) implement IEquatable.. which I presume it doesn't.. – Brett Caswell Nov 16 '15 at 18:19
  • [It does.](https://msdn.microsoft.com/en-us/library/system.int32.aspx) My examples all compile and work properly :) – poke Nov 16 '15 at 18:20
  • I'm not seeing why you make `expectedResult` a separate parameter, if it doesn't get treated any different from any value in `calculations`. To me, it seems simpler to write it as `public static bool AllEqual(params T[] calculations) { return calculations.Distinct().Count() == 1; }` (if you want to keep using the LINQ helper functions). But still a nice answer either way. –  Nov 16 '15 at 18:26
  • @hvd, because the logic isn't really determining whether all instance equal one another, it's determining whether all instances equal the expectedResult. (OP "to a single answer") – Brett Caswell Nov 16 '15 at 18:29
  • 1
    @BrettCaswell There's no difference in the result, but if you want to treat them as conceptually different, fair enough, but then `AllEqual` is not a good name: `AllEqual(a, b, c)` doesn't indicate which of those is the expected value. –  Nov 16 '15 at 20:16
  • 1
    @hvd It’s meant as “all equal to `expectedResult`…”. Anyway, yes, it may have the same result but there is still a semantical difference between the solutions. But I never claimed that my solution would have been the only possibility, or the best, or whatever. And with the question being rather vague, I don’t see why you are arguing about this :) – poke Nov 16 '15 at 20:19
  • @hvd .. actually, we should all be naming our parameters at this point `AllEqual(expectedResult: a, calculations: [] { b, c })`. the method name could be better I suppose: perhaps just be `Equals`; for, we're extending `Equals` not `All`.. still, there is a clear usage issue if you attempt to do just `params`, IEnumerable and Array do not have an add and param only allows using IEnumerable or listing each instance of that IEnumerable.. so you couldn't do `AllEqual(4, caculations)`. lastly, implicitly using expectedResult from the param (first, or last) is.terribly ambiguous usage.. – Brett Caswell Nov 16 '15 at 21:14
  • wait.. `Object.Equals` doesn't already take `param` for `objb` parameter, does it?.. – Brett Caswell Nov 16 '15 at 21:17
  • @BrettCaswell My point was that it doesn't make any difference which of those (if any) is the expected result, so to me, the fact that none is clearly indicated as such is not a problem in the first place, all values affect the result in exactly the same way. I must admit that "so you couldn't do `AllEqual(4, caculations)`" is a very convincing argument, though. –  Nov 16 '15 at 21:19
2

If you wanted to reduce repition, a Linq query works quite well:

IEnumerable<int> fourExpressions = new List<int>{ 2 + 2, 2 * 2, ... };
bool allEqualToFour = fourExpressions.All(x => x == 4);
if (allEqualToFour) { ... }

or as one line

if (new int[]{ 2 + 2, 2 * 2 }.All(x => x == 4)) { ... }

or (ab)using extension methods for maximum briefness. (Generally, polluting all objects with a helper method like this is not the best idea, so this method could well be left as a static method.)

public static class QuestionableExtensions
{
    public static bool EqualsAllOf<T>(this T value, params T[] collection) where T : IEquatable<T>
    {
        return collection.All(t => value.Equals(t));
    }
}

public class MyClass 
{
    public void MyMethod()
    {
        if (4.EqualsAllOf(2 * 2, 2 + 2)) { ... }
    }
}

The following page has a nice collection of links explaining Linq queries.

walpen
  • 379
  • 2
  • 11
  • hmm... `IEnumerable` is not `Linq`, `All` is not a `Linq` expression.. there is no `Linq` here at all.. you could use this method in .NET 2.0 – Brett Caswell Nov 16 '15 at 18:36
  • 1
    @BrettCaswell `All` is an extensions method defined in [`System.Linq`](https://msdn.microsoft.com/en-us/library/system.linq.immutablearrayextensions(v=vs.111).aspx). I agree that this does not use the `Linq` query syntax, but that's just syntax sugar for (in this case) `System.Linq` methods. – walpen Nov 16 '15 at 18:43
1

You can use this extension method

public static bool SameAs<T>(this T val, params T[] values) where T : struct
{
    return values.All(x => x.Equals(val));
}

if (4.SameAs(2*2,2+2)) { ... }
Hamid Pourjam
  • 20,441
  • 9
  • 58
  • 74
1

In reference to @walpen's answer pointing out All is a Linq extension (defined in System.Linq.Enumerable).

I wanted to provide a .NET 2.0 implementation of All, as an extension.

First, we'll define an Attribute called ExtensionAttribute. (SO reference: Using extension methods in .NET 2.0?)

namespace System.Runtime.CompilerServices
{
    [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class
         | AttributeTargets.Method)]
    public sealed class ExtensionAttribute : Attribute { }
}

Then, ( by way of magic) we can use the this reference for extensions. So, we'll create a static class for the usage of the ExtensionAttribute: I choose to do so by defining a static class named Enumerable in System.Collections.Generic namespace.

namespace System.Collections.Generic
{
    public static class Enumerable
    {
        //[System.Runtime.CompilerServices.Extension()]
        public static bool All<T>(this IEnumerable<T> list, T expectedAnswer)
            where T : IEquatable<T>, IComparable<T>
        {
            bool result = true;    
            IEnumerator<T> enumerator = list.GetEnumerator();

            while (enumerator.MoveNext())
            {
                result = result && (Object.Equals(enumerator.Current, expectedAnswer));

                if (!result)
                    return result;
            }
            return result;
        }

        public delegate bool MyFunc<T>(T next);


        public static bool All<T>(this IEnumerable<T> list, MyFunc<T> fn)
            where T : IEquatable<T>, IComparable<T>
        {
            bool result = true;    
            IEnumerator<T> enumerator = list.GetEnumerator();

            while (enumerator.MoveNext())
            {
                result = result && fn.Invoke(enumerator.Current);

                if (!result)
                    return result;
            }
            return result;
        }
    }
}

Then, it's a simple matter of using it.

IEnumerable<int> ints = new int[] { 2 + 2, 2 * 2, 1 * 3 + 1 };
Console.Write("Result := {0}", ints.All(4)); // outputs "Result := true"
Console.Write("Result := {0}", ints.All(t => t.Equals(4))); // outputs "Result := true"
Community
  • 1
  • 1
Brett Caswell
  • 1,486
  • 1
  • 13
  • 25
  • the `t => t.Equals(4)` part is a bit suspect, for I think that is a newer C# implementation.. thus you have a new IDE, msbuild that targets an older framework.. – Brett Caswell Nov 16 '15 at 19:58
-1

Just tossing a random idea out there

if (new Int32[] { 2 * 2, 2 + 2, ... }.All(t => t == 4))
{
    MessageBox.Show("Yup");
}
else
{
    MessageBox.Show("Nope");
}

Sorry, sorry I misread I removed my previous code. This perform the OP's logic.

All is the only way I can find to do this.

Mogsdad
  • 44,709
  • 21
  • 151
  • 275
David Carrigan
  • 751
  • 1
  • 8
  • 21
  • hmm.. that's not really following the logic of what he's trying to do, I think... – Brett Caswell Nov 16 '15 at 18:10
  • that is, if he did `new Int32[] { 2 + 2, 2 * 2, 3*3 }` it would still contain `4` right? – Brett Caswell Nov 16 '15 at 18:11
  • Still wrong, it displays "Yup" if the test succeeds for both values, but also if the test fails for both values, e.g. with `new Int32[] { 3+3, 3*3 }` – Galax Nov 16 '15 at 18:22
  • 1
    yeah.. `all` is pretty much going to be the only appropriate method to use on an array for this logic.. but it's worth noting that int does implement `IEquatable`, (which is likely what `All` utilizes in it's implementation).. – Brett Caswell Nov 16 '15 at 18:31