C# 当三个变量中的任何一个都可以是通配符时,检查这三个变量是否相等的优雅方法是什么?
假设我有3个C# 当三个变量中的任何一个都可以是通配符时,检查这三个变量是否相等的优雅方法是什么?,c#,puzzle,equality,C#,Puzzle,Equality,假设我有3个char变量,a,b和c 每个字符都可以是'0',这是一个特例,意味着它匹配每个字符 因此,如果a是'0',我只需要检查b==c 我想检查a==b==c,但发现c中的实现变得混乱而冗长 你能提供什么创造性的或漂亮的解决方案吗 更新 对于性能驱动,采用Erik A.Brandstadmoen的方法。 为了简单起见,使用M4N的方法,我也做了一些修改:!(query.Any() var a = '1'; var b = '0'; var c = '1'; var chars = new
char
变量,a
,b
和c
每个字符都可以是
'0'
,这是一个特例,意味着它匹配每个字符
因此,如果a是'0'
,我只需要检查b==c
我想检查a==b==c,但发现c中的实现变得混乱而冗长 你能提供什么创造性的或漂亮的解决方案吗 更新 对于性能驱动,采用Erik A.Brandstadmoen的方法。 为了简单起见,使用M4N的方法,我也做了一些修改:
!(query.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;
这算是混乱和冗长吗
对我来说似乎没问题,前提是你只能拥有他们三个
return ((a == "0" || b == "0" || a == b) && (b =="0" || c =="0" || b == c) && (a =="0" || c =="0" || a == c));
优雅的解决方案
这需要对LINQ有基本的了解,并基于:
简单的解决方案
这是代码中逻辑的纯翻译,没有什么花哨的东西
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
第二个重载只是为每对调用第一个重载
(请注意,由于通配符,我们无法使用transitive属性并仅比较两对。)
我不确定我会称之为优雅,但它并不可怕(甚至可能是正确的…)(注意,这或多或少是对Paddy上述答案的改进)。您可以编写一个结构“MYChar”,实现char
并覆盖等于
、相等运算符和隐式转换,因此您可以:
MyChar a = 'a';
MyChar b = '0';
bool eq = a == b; //true
编辑
原来您无法从char
继承,因为它是密封的,但我尝试了以下代码。它可以编译,但我不确定它是否有效。我从中编译了它,但当时我没有任何东西要测试
下面是:
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 ();
}
}
对于任意数量的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));
}
}
如果将字符限制为ASCII而不是unicode,那么我喜欢:
. (编辑回应评论指出我没有完全正确的规格,但我仍然喜欢基本的想法。添加了额外的测试作为验证)
对于包含无限个字符的更通用的解决方案,这就是正则表达式的作用:^()(\1 | 0)*$这与公认的答案没有太大区别,但无论如何
var list = new List<Char> {'1', '1', '0'};
var check = list.Where(ch => ch != '0')
.Distinct()
.Count() < 2;
var list=新列表{'1','1','0'};
var check=list.Where(ch=>ch!=“0”)
.Distinct()
.Count()<2;
关于:
if ((a==b) && (b==c) && (a==c))
....
....
我的逻辑错了吗?@BoltClock:逻辑是a==b==c
,如果其中任何一个是0
,那么它被认为是自动匹配的。“每个都可以是“0”,这意味着它匹配每个字符。”?@Yuck:你的意思是,如果其中任何一个是“0”,那么其他两个就根本不必匹配了吗?按照我的理解,假设a='t'
,b='t'
和c=0
…这应该返回true
,这意味着所有3个变量都“匹配”。对我来说,这看起来非常混乱和冗长。@Dan为什么第三次检查没有失败?@Arafinwe:在我发表评论时它不在那里:-)Paddy,最初我无法评论b/c我没有足够的代表性,因此我很抱歉直接编辑您的问题而不是仅仅评论,但编辑实际上是正确的-正如我在编辑中留下的评论所指出的,@Dan Abramov的假阳性为“4 0 5”(如果b==0,则无论其他变量的值如何,您的结果都是正确的…)你认为检查chars会更容易吗?其中(c=>c!=“0”).Distinct().Count()我还认为,关于代码可读性,chars.Count()==0
有点误导(因为chars
已经过滤了通配符,但这表明我们正在检查原始字符)。还有,这类支票有任何。很好,我想现在看起来好多了。非常感谢。60年代的人打电话来,想要回他们的名单和lambda
。“所有这一切以前都发生过,将来也会发生。”(我用一种略带讽刺但完全支持的方式表达这一评论。)非常好的解决方案,它是对原始问题的完美回答。但是,如果要对任意大小的数组/列表运行此操作,则使用Distinct
并不是一种非常有效的表示不存在的方式(用SQL来说)。假设您有一个包含一百万个元素的数组,其中第一个元素是1和2,您将遍历所有元素以获得Distinct
的结果,因为我下面的回答将在第二个元素上返回false。请注意。您可能应该将其设置为struct
(并且不要忘记实现IEquatable
)。实际上,它必须是一个struct。我不会在这里实现IEquatable,但肯定这是一个好主意。是的,有必要避免持续的(非)拳击。这就是我,还是你在建造一艘飞行500米的宇宙飞船?@Erik:不太可能,他需要一个处理通配符的字符,我建造了一个处理通配符的字符。完成后,您可以向其添加任何通配符或任何需要的功能。<2可以是=!2但通过这种方式,您可以检查3个以上的项。从原始问题“如果a为'0',我只需要检查b==c”,因此这里的“通配符”概念并不表示立即匹配,而是应该忽略该字符。因此,除000和aaa之外的所有测试都应返回False,并且此解决方案无法捕获询问者的意图。@johnny:你说得对,更改了条件和测试。这使得它不太优雅,但仍比将其添加到列表中要好)。实际显示了预期的准确结果;从最初的问题:“如果a是‘0’,我只需要检查b==c”,例如,像a0a或bb0这样的东西应该是真的,而a0c或ab0应该是假的,所以提供的所有测试除了aa
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));
}
}
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
}
}
var list = new List<Char> {'1', '1', '0'};
var check = list.Where(ch => ch != '0')
.Distinct()
.Count() < 2;
if ((a==b) && (b==c) && (a==c))
....
....