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

发布于 2024-11-29 02:24:48 字数 439 浏览 1 评论 0原文

假设我有 3 个 char 变量:abc
每个都可以是'0',这是一种特殊情况,意味着它匹配每个字符。

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

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

更新

性能驱动的 ,采用 Erik A. Brandstadmoen 的方法。 为了简单起见,使用M4N的apprach,我也做了一些修改: !(query.Any() && query.Distinct().Skip(1).Any())

Say I have 3 char variables, a, b and c.
Each one can be '0', which is a special case and means it matches every char.

So if a is '0', I only need to check if b == c.
I want to check if a == b == c, but found the implementation in C# goes chaotic and lengthy.

Is there any creative or pretty solution you can offer?

update

for performance driven, take Erik A. Brandstadmoen's approach.
for simplicity, use M4N's apprach, also i did some modification: !(query.Any() && query.Distinct().Skip(1).Any())

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

傻比既视感 2024-12-06 02:24:48

像这样的事情:

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

Something like this:

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;

To explain the solution:

  • first put all chars into a list
  • exclude all chars which are '0': .Where(ch => ch != '0')
  • all remaining chars are equal if either:
    • the remaining collection contains no elements: chars.Count() == 0
    • or the number of unique remaining elements is 1: chars.Distinct().Count() == 1

Update: here's a different version, which does not use LINQ but is still and readable (IMO). It is implemented as a method and can be called with any number of characters to be tested:

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
逆光下的微笑 2024-12-06 02:24:48

优雅的解决方案

这需要对 LINQ 有基本的了解,并且基于 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);
}

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

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

The Elegant Solution

This requires basic understanding of LINQ and is based on the solution by M4N:

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

Edit

Originally my solution was different from M4N's solution but after some simplifications, I came to something (almost) exactly the same. While credits go completely to him, I'll just leave it for reference.

It returns true when there is at most one distinct non-wildcard character in the collection.
I made it accept a variable number of parameters so you may call it for 2, 3 or more chars:

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

The Simple Solution

This is pure translation of your logic in your code, no fancy stuff.

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);
}

First IsMatch overload returns true when its argument are equal or one of them is '0'.
The second overload simply calls the first one for each pair.

(Note that due to wildcards we cannot use the transitive property and compare just two pairs.)

梦言归人 2024-12-06 02:24:48

像这样的东西应该适用于任意数量的 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));
    }
}

Something like this should work for any number of char values:

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');
    }
}

Passes the following unit tests:

[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));
    }
}
梦冥 2024-12-06 02:24:48
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);
}

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

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);
}

Not sure I'd call it elegant, but it isn't horrible (and might even be correct...) (note, this is more or less a refinement of Paddy's answer above).

听不够的曲调 2024-12-06 02:24:48

您可以编写一个结构“MYChar”,它实现 char 并覆盖 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 ();
    }
}

You could write a struct "MYChar" that implements char and overrides Equals, equality operators and implicit conversion so you could do :

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

bool eq = a == b; //true

Edit

It turns out that you can't inherit from char because it is sealed, but I tried the following code. It compiles, but I'm not sure it works. I compiled it from http://compilr.com/IDE/34853, but I don't have anything to test at the time.

here it goes :

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 ();
    }
}
纵山崖 2024-12-06 02:24:48

这算不算混乱且冗长?

对我来说似乎没问题,前提是你只能拥有他们三个......

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

Does this count as chaotic and lengthy?

Seems ok for me, providing you can only ever have the three of them...

return ((a == "0" || b == "0" || a == b) && (b =="0" || c =="0" || b == c) && (a =="0" || c =="0" || a == c));
櫻之舞 2024-12-06 02:24:48

如果你将字符限制为 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)*$

If you limit chars to ASCII and not unicode then, I like:
http://ideone.com/khacx. (editted in response to comment pointing out I hadn't quite got the specs right, but I still like the basic idea. Added additional test as verification).

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
     }
}

For a more general solution that covers an unlimited number of characters, thats what regexs are for: ^(.)(\1|0)*$

秋意浓 2024-12-06 02:24:48

怎么样:

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

我的逻辑错了吗?

What about:

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

Is my logic wrong?

楠木可依 2024-12-06 02:24:48

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

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

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

That is not very different from the accepted answer but anyway

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

var check = list.Where(ch => ch != '0')
                .Distinct()
                .Count() < 2;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文