当3个变量中的任何一个可以是通配符时,检查它们是否相等的优雅方法是什么
本文关键字:是否 检查 是什么 方法 任何一 变量 3个 通配符 | 更新日期: 2023-09-27 18:05:25
假设我有3个char
变量,a
、b
和c
每个字符都可以是'0'
,这是一种特殊情况,意味着它匹配每个字符。
所以如果a是'0'
,我只需要检查一下b == c
我想检查a == b == c
,但发现C#中的实现混乱且冗长。
你能提供什么有创意或漂亮的解决方案吗?
更新
对于性能驱动,请采用Erik A.Brandstadmoen的方法。为了简单起见,使用M4N的appach,我还做了一些修改:!(query.Any() && query.Distinct().Skip(1).Any())
类似这样的东西:
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
优雅的解决方案
这需要对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);
}
当第一个IsMatch
重载的自变量相等或其中一个为'0'
时,它返回true
第二个重载只是为每对调用第一个重载。
(请注意,由于通配符的原因,我们不能使用可传递属性并仅比较两个对。(
类似的东西应该适用于任何数量的字符值:
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));
}
}
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);
}
我不确定我会称之为优雅,但它并不可怕(甚至可能是正确的……((注意,这或多或少是对帕迪上述答案的改进(。
您可以编写一个实现char
并重写Equals
、相等运算符和隐式转换的结构体"MYChar",这样您就可以执行:
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 ();
}
}
这算不算混乱和冗长?
对我来说似乎还可以,只要你只能拥有他们三个。。。
return ((a == "0" || b == "0" || a == b) && (b =="0" || c =="0" || b == c) && (a =="0" || c =="0" || a == c));
如果您将字符限制为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
}
}
对于一个涵盖无限字符数的更通用的解决方案,regexs的作用是:^(.((''1|0(*$
关于:
if ((a==b) && (b==c) && (a==c))
....
....
我的逻辑错了吗?
这与公认的答案没有太大区别,但无论如何
var list = new List<Char> {'1', '1', '0'};
var check = list.Where(ch => ch != '0')
.Distinct()
.Count() < 2;