C# 如果语句-';或';但不是';和';
在C语言中,如何设置一个if语句来检查几个条件中的一个是否为真?它只能是其中一个条件,如果零或两个或多个条件为真,则if应为假。为了简单起见,您可以保留一个运行计数:C# 如果语句-';或';但不是';和';,c#,if-statement,C#,If Statement,在C语言中,如何设置一个if语句来检查几个条件中的一个是否为真?它只能是其中一个条件,如果零或两个或多个条件为真,则if应为假。为了简单起见,您可以保留一个运行计数: int totalTrue = 0; if (A) totalTrue++; if (B) totalTrue++; if (C) totalTrue++; ... return (1 == totalTrue); 您可以使用将布尔值组合成bool序列,然后应用LINQ: bool[] conditions = new bool
int totalTrue = 0;
if (A) totalTrue++;
if (B) totalTrue++;
if (C) totalTrue++;
...
return (1 == totalTrue);
您可以使用将布尔值组合成
bool
序列,然后应用LINQ:
bool[] conditions = new bool[] { cond1, cond2, cond3, cond4 };
bool singleTrue = conditions.Count(cond => cond) == 1;
对于两个布尔人来说,独占or变得简单得多:
bool singleTrue = cond1 != cond2;
编辑:为了实现按需评估和短路,我们需要将bool
序列升级为Func
序列(其中每个元素都是封装条件评估的函数委托):
测试的样本数据(可在每个false
或true
上设置断点,以进行评估):
IEnumerable conditions=new Func[]
{
() =>
假,,
() =>
是的,
() =>
假,,
() =>
假,,
};
您可以编写一个助手方法。这样做的好处是它会短路,只需根据需要准确评估
public static bool IsExactlyOneTrue(IEnumerable<Func<bool>> conditions) {
bool any = false;
foreach (var condition in conditions) {
bool result = condition();
if (any && result) {
return false;
}
any = any | result;
}
return any;
}
公共静态bool IsExactlyOneTrue(IEnumerable条件){
bool any=false;
foreach(条件中的var条件){
bool结果=条件();
如果(任何&&结果){
返回false;
}
any=任何|结果;
}
退回任何文件;
}
我想这就可以了
int i= 0;
if ( (!A || ++i <= 1) &&
(!B || ++i <= 1) &&
(!C || ++i <= 1) &&
... &&
(i == 1))
inti=0;
如果(!A | |++iList criteria=new List();
添加(c=>c.Name.StartsWith(“B”);
添加(c=>c.Job==Jobs.Plumber);
添加(c=>c.IsExcellent);
Customer myCustomer=GetCustomer();
int criteriaCount=标准
.其中(q=>q(我的客户))
//.Take(2)//优化
.Count()
如果(标准计数==1)
{
}
Jason方法签名的Linq实现:
public static bool IsExactlyOneTrue(IEnumerable<Func<bool>> conditions)
{
int passingConditions = conditions
.Where(x => x())
// .Take(2) //optimization
.Count();
return passingConditions == 1;
}
公共静态bool IsExactlyOneTrue(IEnumerable条件)
{
int passingConditions=条件
.其中(x=>x())
//.Take(2)//优化
.Count();
返回传递条件==1;
}
这些答案中的大多数都是有效的,并且具有“良好的性能”。但最简单的答案是:
if( (A & !(B || C)) ||
(B & !(A || C)) ||
(C & !(A || B)) )
{
...
}
你会不止一次地计算A/B/C,所以这只有在你有简单的布尔值时才有用。这有一个缺点,那就是必须计算所有的条件。这可以通过将其更改为AFunc[]
并使用条件来解决。其中(cond=>cond()).Skip(1)。Any();
@TimS.:不会Skip(1)
当所有值都为false时失败?嗯…它不会像抛出时那样“失败”,但它的行为不太正确-它返回true。我在对Jason的答案的评论中发布了一个修订。回答很好。也可以在与特定类型无关的情况下执行:var conditions=new List();conditions.Add(()=>foo==bar);如果(conditions.Select(x=>x.Invoke()).Count(x=>x)==1){}
当然,您只是将特定实例推到criteria中。我的“criteria”收集延迟了拥有一个适用实例的需要,并且可以重复使用尽可能多的实例。这种方法需要评估所有条件,无论是否必要。我更喜欢允许短路的方法。不。只需取消注释Take,执行就会在第一时间停止。@David B:theTake现在没有取消注释,是吗?此方法可以简化为return!条件。其中(cond=>cond()).Skip(1).Any()
它的可读性更高,运行速度可能会慢一些,但除非发现这一点非常重要,否则我会选择更简洁的。进一步看,这必须更像这样才能正常工作:var trueConditions=conditions.Where(cond=>cond());if(!trueConditions.Take(1).Any())return false;return!trueConditions.Skip(1).Any();
我开始比我的LINQ方法更喜欢你的答案了。@TimS::但这可能会导致前面的假结果表达式被计算两次。我认为在LINQ中没有任何优雅的方法可以做到这一点(除非通过预测指数,否则无法达到全部目的).确实如此。我只是用一个假表达式测试了它,然后用一个真表达式测试了它,每个表达式计算了两次。它可能是可以修复的,但它的复杂性越来越大,远远超过了Jason的解决方案。LINQ只是不能很好地处理这种情况。@TimS.:我做了更多的实验,发现如果假设存在,它可以在LINQ中优雅地完成基于谓词的IndexOf
运算符的tence(易于定义)请看下面我的编辑答案。我个人将最后一个语句写为<代码>返回ToalTrime= 1;。我了解向后写这些测试的理由,但我不同意它,括号是不必要的。@ Keththoppson,我只想让自己习惯于按顺序写代码,以防我回到C++。Adam V:在罗马,做罗马人的事。C和C++不是同一种语言。不要在C++中写C语言,在C语言中不要用C++。杰森:如果是无效的代码,或者在语言之间改变了意思的代码,我同意你的看法。但是,因为它只是一种习惯,我会保留它。Adam V:这是事实。当C程序员读C代码时,他们期望看到C。在C#中输入。语言中有一些习语,与这些习语相反的代码会让人分心。@Tim S。在其他几个不同答案的评论中输入你的答案是很不礼貌的。删除这些评论,将你的答案作为答案发布,并接受投票的判断——正如Jeff所想的那样。
int i= 0;
if ( (!A || ++i <= 1) &&
(!B || ++i <= 1) &&
(!C || ++i <= 1) &&
... &&
(i == 1))
List<Func<Customer, bool>> criteria = new List<Func<Customer, bool>>();
criteria.Add(c => c.Name.StartsWith("B"));
criteria.Add(c => c.Job == Jobs.Plumber);
criteria.Add(c => c.IsExcellent);
Customer myCustomer = GetCustomer();
int criteriaCount = criteria
.Where(q => q(myCustomer))
// .Take(2) // optimization
.Count()
if (criteriaCount == 1)
{
}
public static bool IsExactlyOneTrue(IEnumerable<Func<bool>> conditions)
{
int passingConditions = conditions
.Where(x => x())
// .Take(2) //optimization
.Count();
return passingConditions == 1;
}
if( (A & !(B || C)) ||
(B & !(A || C)) ||
(C & !(A || B)) )
{
...
}