当任何一个变量可以是通配符时,检查3个变量是否相等的优雅方法是什么?

时间:2011-08-10 19:47:32

标签: c# puzzle equality

说我有3个char变量,abc
每一个都可以是'0',这是一个特例,意味着它匹配每个字符。

因此,如果a为'0',我只需要检查b == c是否 我想检查是否a == b == c,但发现C#中的实现变得混乱和冗长。

您可以提供任何创意或漂亮的解决方案吗?

更新

对于绩效驱动,采取Erik A. Brandstadmoen的方法。 为简单起见,使用M4N的apprach,我也进行了一些修改:!(query.Any() && query.Distinct().Skip(1).Any())

9 个答案:

答案 0 :(得分:35)

这样的事情:

var a = '1';
var b = '0';
var c = '1';

var chars = new List<char> { a, b, c };
var filtered = chars.Where(ch => ch != '0');
var allEqual = filtered.Count() == 0 || filtered.Distinct().Count() == 1;

解释解决方案:

  • 首先将所有字符放入列表
  • 排除所有字符为'0':.Where(ch => ch != '0')
  • 如果其中任何一个,所有剩余的字符相等:
    • 其余集合不包含任何元素:chars.Count() == 0
    • 或唯一剩余元素的数量为1:chars.Distinct().Count() == 1

更新:这是一个不同的版本,它不使用LINQ但仍然可读(IMO)。它作为一种方法实现,可以使用任意数量的字符进行调用:

public bool AllEqualOrZero(params char[] chars)
{
    if (chars.Length <= 1) return true;
    char? firstNonZero = null;
    foreach (var c in chars)
    {
        if (c != '0')
        {
            firstNonZero = firstNonZero ?? c;
            if (c != firstNonZero) return false;
        }
    }
}

// Usage:
AllEqualOrZero('0', '0', '0'); // -> true
AllEqualOrZero('0', '1', '1'); // -> true
AllEqualOrZero('2', '1', '0'); // -> false
AllEqualOrZero();              // -> true
AllEqualOrZero('1');           // -> true

答案 1 :(得分:18)

优雅的解决方案

这需要对LINQ有基本的了解,并且基于solution by M4N

static bool IsMatch(params char[] chars)
{
    return chars.Where(c => c != '0')
                .Distinct().Count() <= 1;    
}
  

修改

     

最初我的解决方案 与M4N的解决方案不同,但经过一些简化后,我得到的东西(几乎)完全相同。虽然积分完全归功于他,但我会留下它作为参考。

当集合中最多有一个不同的非通配符时,它会返回true
我让它接受了可变数量的参数,因此您可以将其称为2个,3个或更多个字符:

bool match = IsMatch('3', '3', '4', '0');

简单解决方案

这是您的代码中逻辑的纯粹翻译,没有花哨的东西。

static bool IsMatch(char x, char y)
{
    return x == y || x == '0' || y == '0';
}

static bool IsMatch(char a, char b, char c)
{
    return IsMatch(a, b) && IsMatch(b, c) && IsMatch(a, c);
}

首先IsMatch重载在其参数相等或其中一个为true时返回'0'
第二个重载只是为每对调用第一个。

(请注意,由于通配符,我们无法使用传递属性并只比较两对。)

答案 2 :(得分:2)

这算是混乱而冗长吗?

对我来说似乎没问题,只要你能拥有其中的三个......

return ((a == "0" || b == "0" || a == b) && (b =="0" || c =="0" || b == c) && (a =="0" || c =="0" || a == c));

答案 3 :(得分:2)

bool MatchTwo(char a, char b)
{
    return a == '0' || b == '0' || a == b;
}

bool MatchThree(char a, char b, char c)
{
    return MatchTwo(a, b) && MatchTwo(a, c) && MatchTwo(b, c);
}

不确定我会称之为优雅,但它并不可怕(甚至可能是正确的......)(请注意,这或多或少是对上述Paddy答案的改进)。

答案 4 :(得分:2)

您可以编写一个实现char的结构“MYChar”并覆盖Equals,等式运算符和隐式转换,以便您可以这样做:

MyChar a = 'a';
MyChar b = '0';

bool eq = a == b; //true

修改

事实证明你不能继承char,因为它是密封的,但我尝试了以下代码。它编译,但我不确定它是否有效。我是从http://compilr.com/IDE/34853编译的,但我当时没有要测试的东西。

在这里:

public struct MyChar
{
    private static char _wild = '0';

    private char _theChar;

    public MyChar(char c)
    {
        _theChar = c;
    }

    public MyChar ()
        :this (_wild)
    {}

    private bool IsWildCard ()
    {
        return _theChar.Equals (_wild);
    }        

    public static implicit operator char (MyChar c)
    {
        return c._theChar;
    }

    public static implicit operator MyChar (char c)
    {
        return new MyChar (c);
    }


    public override bool Equals (object obj)
    {
        if (!(obj is MyChar))
        {
            return base.Equals (obj);
        }
        else
        {
            if (IsWildCard ())
            {
                return true;
            }
            else
            {
                MyChar theChar = (MyChar) obj;
                return theChar.IsWildCard () || base.Equals ((char) theChar);
            }
        }
    }

    public override int GetHashCode ()
    {
        return _theChar.GetHashCode ();
    }
}

答案 5 :(得分:2)

这样的东西应该适用于任意数量的char值:

public class Comparer
{
    public static bool AreEqualOrZero(params char[] values)
    {
        var firstNonZero = values.FirstOrDefault(x => x != '0');
        return values.All(x => x == firstNonZero || x == '0');
    }
}

通过以下单元测试:

[TestClass()]
public class ComparerTest
{

    [TestMethod()]
    public void Matches_With_Wildcard()
    {
        char[] values = {'0', '1', '1', '1'};
        Assert.IsTrue(Comparer.AreEqualOrZero(values));
    }

    [TestMethod()]
    public void Matches_With_No_Wildcard()
    {
        char[] values = {'1', '1', '1', '1'};
        Assert.IsTrue(Comparer.AreEqualOrZero(values));
    }

    [TestMethod()]
    public void Matches_With_Only_Wildcards()
    {
        char[] values = {'0', '0', '0'};
        Assert.IsTrue(Comparer.AreEqualOrZero(values));
    }

    [TestMethod()]
    public void Matches_With_Zero_Length()
    {
        char[] values = {};
        Assert.IsTrue(Comparer.AreEqualOrZero(values));
    }

    [TestMethod()]
    public void Matches_With_One_Element()
    {
        char[] values = {'9'};
        Assert.IsTrue(Comparer.AreEqualOrZero(values));
    }

    [TestMethod()]
    public void Matches_With_One_Wildcard_And_Nothing_Else()
    {
        char[] values = {'0'};
        Assert.IsTrue(Comparer.AreEqualOrZero(values));
    }

    [TestMethod()]
    public void Does_Not_Match_On_NonEqual_Sequence_No_Wildcard()
    {
        char[] values = {'1', '2', '1', '1'};
        Assert.IsFalse(Comparer.AreEqualOrZero(values));
    }

    [TestMethod()]
    public void Does_Not_Match_On_NonEqual_Sequence_With_Wildcard()
    {
        char[] values = {'1', '2', '1', '0'};
        Assert.IsFalse(Comparer.AreEqualOrZero(values));
    }
}

答案 6 :(得分:2)

如果你将字符限制为ASCII而不是unicode,那么我喜欢: http://ideone.com/khacx。 (编辑回应评论指出我没有完全正确的规格,但我仍然喜欢基本的想法。添加额外的测试作为验证)。

using System;
class example {
    static void elegant(char a, char b, char c) {
      int  y =  ((int) a - 48) + ((int) b - 48) + ((int) c - 48);
      int  z =  ((int) a - 48) * ((int) b - 48) * ((int) c - 48);

      bool result = y == ((int) a-48)*3 || (z ==0 && (a==b || b==c || a==c));
      Console.WriteLine(result);
    }
    static void Main() {

      elegant('0', 'b', 'c'); // false
      elegant('a', '0', 'c'); // false
      elegant('a', 'b', '0'); // false
      elegant('a', 'b', 'c'); // false
      elegant('0', '0', '0'); // true
      elegant('a', 'a', 'a'); // true
      elegant('0', 'a', 'a'); // true
      elegant('a', '0', 'a'); // true
      elegant('a', 'a', '0'); // true
      elegant('0', '0', 'a'); // true
      elegant('0', 'a', '0'); // true
      elegant('a', '0', '0'); // true
     }
}

对于涵盖无限数量字符的更一般的解决方案,这就是正则表达式的用途:^(。)(\ 1 | 0)* $

答案 7 :(得分:1)

怎么样:

if ((a==b) && (b==c) && (a==c)) 
....
....

我的逻辑错了吗?

答案 8 :(得分:0)

这与接受的答案没有太大差别,但无论如何

var list = new List<Char> {'1', '1', '0'};

var check = list.Where(ch => ch != '0')
                .Distinct()
                .Count() < 2;