关闭。这个问题是基于意见的。它目前不接受答案。想改进这个问题?更新问题,以便可以通过编辑这篇文章用事实和引用来回答它。 3年前关闭。改进这个问题
我想在 0 和 1 之间切换一个变量。如果它是 0,我想将它设置为 1,否则如果它是 1,我想将它设置为 0。
这是一个如此基本的操作,以至于我经常写,我想研究最短、最清晰的方法。这是我迄今为止最好的:
v = (v == 0 ? 1 : 0);
你能改进一下吗?
编辑:问题是询问如何在保持清晰的同时用最少的字符编写上述语句 - 这怎么会“不是一个真正的问题”?这并不打算成为一个代码高尔夫练习,尽管一些有趣的答案已经从人们将它当作高尔夫来对待——很高兴看到高尔夫以一种建设性和发人深省的方式被使用。
v = +!v;
您可以简单地使用:
v = 1 - v;
这当然假设变量已正确初始化,即它只有值 0 或 1。
另一种更短但使用不太常见的运算符的方法:
v ^= 1;
编辑:
要清楚;我从来没有把这个问题当作代码高尔夫来处理,只是为了找到一种完成任务的捷径,而不使用任何模糊的技巧,比如运算符的副作用。
因为 0
是 false
值,而 1
是 true
值。
v = (v ? 0 : 1);
如果您乐于使用 true
和 false
而不是数字
v = !v;
或者如果它们必须是数字:
v = +!v; /* Boolean invert v then cast back to a Number */
+
放在 !
之前。哦,看起来太脏了!但很酷:p
switch(v){ case 0 ...
或 if(v == 0) 或 v === 0,这将破坏他的代码。除了他的方法之外,你正在改变他的结果......
({v :+! v}).v
。
+
标志! ¯\_(ツ)_/¯
v = (v ? 0 : 1)
+1 作为清晰和惯用的 JS。
v = (v + 1) % 2
,如果您需要循环显示更多值,只需将 2
更改为 (n + 1)
。假设您需要循环 0、1、2,只需执行 v = (v + 1) % 3
。
const
变量来代替幻数 2、3、...
++v % 3
如果你想循环通过 0、1、2
您可以为它编写一个函数并像这样使用它:
v = inv(v)
inv
函数中的内容:P)
inv
是一个描述性名称吗?
如果您不关心1以外的任何可能性:
v = v ? 0 : 1;
在上述情况下,如果 v 为 0、false、未定义或 null,则 v 最终将为 1。小心使用这种方法——即使 v 是“hello world”,v 也会为 0。
v = v ? 0 : 1
。
v = 1 - v
、v ^= 1
或 v= +!v
之类的行都可以完成工作,但它们构成了我所说的 hacks。这些不是漂亮的代码行,而是达到预期效果的廉价技巧。 1 - v
不传达“在 0 和 1 之间切换值”。这会降低您的代码的表现力,并引入一个地方(尽管很小),另一个开发人员将不得不解析您的代码。
相反,拥有像 v = toggle(v)
这样的函数可以以最快的速度传达意图。
v=1-v
没有传达开关?
1-v
确实可以交流切换,但这是它交流的唯一内容。例如,它还可以在 v=1
处传达一条为零的线,或以 v=0.5
为中心的镜像变换。从这个意义上说,它是相对模棱两可的。确实,知道 v
只能是 0
或 1
会限制其预期含义,但这会迫使其他开发人员(或您未来的自己)在能够理解这个简单的行之前理解该上下文。你再清楚不过了 v = toggle(v)
v ^= 1
就非常清楚,如果您是程序员,则最好这样做。我认为这就是那和 v=1-v
之间的区别;一个是逻辑运算,一个是算术运算,我们试图表示一个逻辑概念而不是数学概念。
v ^= 1
也有一些歧义,因为它可以解释为按位异或。
(诚实和数学上的完整性——考虑到这个“答案”的投票数——让我编辑了这个答案。我尽可能地推迟了,因为它是一个简短的俏皮话,而不是任何“深刻”的东西,所以放进去任何解释似乎都与目的背道而驰。但是,评论清楚地表明我应该清楚以避免误解。)
我原来的答案:
这部分规范的措辞:
如果为 0,我想将其设置为 1,否则将其设置为 0。
意味着最准确的解决方案是:
v = dirac_delta(0,v)
首先,坦白:我确实把我的 delta 函数弄糊涂了。 Kronecker delta 会稍微合适一些,但并不像我想要的那样与域无关(Kronecker delta 主要用于整数)。但我真的根本不应该使用 delta 函数,我应该说:
v = characteristic_function({0},v)
让我澄清一下。回想一下,函数是三元组 (X,Y,f),其中 X 和 Y 是集合(分别称为域和余域),f 是将 Y 的一个元素分配给 X 的每个元素的规则。我们经常写三元组 (X,Y,f) 为 f: X → Y。给定 X 的一个子集,比如 A,有一个特征函数是函数 χA: X → {0,1}(也可以认为作为更大的共域的函数,例如ℕ或ℝ)。该函数由以下规则定义:
如果 x ∈ A,则 χA(x) = 1,如果 x ∉ A,则 χA(x) = 0。
如果你喜欢真值表,那就是问题“X 的元素 x 是子集 A 的元素吗?”的真值表。
所以从这个定义中,很明显这里需要特征函数,X 是一个包含 0 和 A = {0} 的大集合。那是我应该写的。
三角函数也是如此。为此,我们需要了解集成。要么你已经知道,要么你不知道。如果你不这样做,我在这里说的任何东西都不会告诉你这个理论的复杂性,但我可以给出一句话总结。对集合 X 的度量本质上是“使平均值起作用所需的度量”。也就是说,如果我们有一个集合 X 和该集合上的测度 μ,那么就有一类函数 X → ℝ,称为可测函数,表达式 ∫X f dμ 是有意义的,并且在某种模糊的意义上是, f 在 X 上的“平均值”。
给定一个集合的度量,可以为该集合的子集定义一个“度量”。这是通过将其特征函数的积分分配给子集来完成的(假设这是一个可测量的函数)。这可以是无限的,也可以是未定义的(两者略有不同)。
周围有很多措施,但这里有两个很重要。一种是实线上的标准度量,ℝ。对于这个度量,那么 ∫ℝ f dμ 几乎就是你在学校学到的东西(微积分还在学校教吗?):总结小矩形并取越来越小的宽度。在这个度量中,间隔的度量是它的宽度。一个点的度量是0。
另一个适用于任何集合的重要度量称为点度量。它被定义为函数的积分是其值的总和:
∫X f dμ = ∑x ∈X f(x)
该度量将度量 1 分配给每个单例集。这意味着子集具有有限度量当且仅当它本身是有限的。并且很少有函数具有有限积分。如果函数具有有限积分,则它必须仅在可数个点上为非零。因此,您可能知道的绝大多数函数在此度量下都没有有限积分。
现在到 delta 函数。让我们来一个非常广泛的定义。我们有一个可测空间 (X,μ)(所以这是一个带有测度的集合)和一个元素 a ∈ X。我们将 delta 函数(取决于 a)“定义”为“函数”δa:X → ℝ 具有 δa(x) = 0 如果 x ≠ a 且∫X δa dμ = 1 的性质。
要掌握的最重要的事实是:delta 函数不必是函数。它没有正确定义:我没有说 δa(a) 是什么。
你在这一点上做什么取决于你是谁。这里的世界分为两类。如果你是数学家,你会说:
好的,所以可能没有定义 delta 函数。让我们看看它的假设属性,看看我们是否可以在它被定义的地方为它找到一个合适的归宿。我们可以做到这一点,我们最终得到分布。这些不是(必然)函数,而是行为有点像函数的东西,我们通常可以像使用函数一样使用它们;但是有些东西他们没有(例如“价值观”),所以我们需要小心。
如果你不是数学家,你可以这样说:
好的,所以 delta 函数可能没有正确定义。谁这么说的?一群数学家?别理他们!他们知道什么?
现在冒犯了我的听众,我将继续。
狄拉克 delta 通常被认为是实线中一个点(通常为 0)与其标准度量的 delta 函数。所以那些在评论中抱怨我不知道我的增量的人这样做是因为他们使用了这个定义。向他们道歉:虽然我可以通过使用数学家的辩护(正如 Humpty Dumpty 所推广的那样:简单地重新定义一切以使其正确)来摆脱这种情况,但使用标准术语来表示不同的东西是不好的形式。
但是有一个 delta 函数可以做我想做的事情,这就是我需要的。如果我对集合 X 进行点测量,则存在一个真正的函数 δa : X → ℝ,它满足 delta 函数的标准。这是因为我们正在寻找一个函数 X → ℝ,它除了在 a 和之外为零,使得它的所有值的总和为 1。这样的函数很简单:唯一缺少的信息是它在 a 处的值,并且为了使总和为 1,我们只需为其赋值 1。这正是 {a} 上的特征函数。然后:
∫X δa dμ = ∑x ∈ X δa(x) = δa(a) = 1。
所以在这种情况下,对于单例集,特征函数和增量函数是一致的。
总之,这里有三个“函数”族:
单例集的特征函数,三角函数,克罗内克三角函数。
其中第二个是最通用的,因为其他任何一个都是使用点测量时的示例。但是第一个和第三个的优点是它们始终是真正的函数。第三个实际上是第一个的特例,用于特定的域族(整数或其中的某个子集)。
所以,最后,当我最初写答案时,我没有正确思考(我不会说我很困惑,因为我希望我刚刚证明我确实知道我在说什么我实际上是首先考虑的,我只是没有想太多)。狄拉克三角洲的通常含义不是这里想要的,但我回答的要点之一是没有定义输入域,因此克罗内克三角洲也不正确。因此,最好的数学答案(我的目标)将是特征函数。
我希望这一切都清楚;我也希望我再也不用用 HTML 实体而不是 TeX 宏来写数学文章了!
通常,每当您需要在两个值之间切换时,您只需从两个切换值的总和中减去当前值即可:
0,1 -> v = 1 - v 1,2 -> v = 3 - v 4,5 -> v = 9 - v
v
损坏,它将突然开始在两个不同的值之间切换。 (只是需要考虑的事情......)
v
通常用于从三个或更多状态的列表中交替执行两个状态,则 v
的损坏可能导致程序交替执行两个完全不同的状态 - 这可能会导致意外和不希望的结果。从中吸取的教训是:始终对您的数据进行合理性检查。
你可以做
v = Math.abs(--v);
递减将值设置为 0 或 -1,然后 Math.abs
将 -1 转换为 +1。
v = Math.round(Math.sin(Math.PI/(v+3)));
v = Math.round(Math.cos(Math.PI/((v*2+1)+2)-2*v));
:D
v = 1
则 v = Math.Abs(-1)
即 +1。如果 v = 0
则 v = Math.Abs(-0)
为 0。
如果它必须是整数 1 或 0,那么你这样做的方式很好,尽管不需要括号。如果这些 a 被用作布尔值,那么你可以这样做:
v = !v;
v = v == 0 ? 1 : 0;
足够的 !
v = (v==0 ? 1 : 0);
”。其他人都在寻找不同的打高尔夫球方式。并没有真正回答这个问题。这就是为什么我投票赞成这个答案。
解决方案列表
我想提出三个解决方案。它们都将任何值转换为 0
(如果是 1
、true
等)或 1
(如果是 0
、false
、null
等):
v = 1*!v
v = +!v
v = ~~!v
以及另外一个,已经提到过,但聪明且快速(虽然仅适用于 0
s 和 1
s):
v = 1-v
解决方案 1
您可以使用以下解决方案:
v = 1*!v
这将首先将整数转换为相反的布尔值(0
到 True
,任何其他值到 False
),然后在乘以 1
时将其视为整数。因此,0
将转换为 1
,任何其他值都将转换为 0
。
作为证明,请参阅此 jsfiddle 并提供您希望测试的任何值:jsfiddle.net/rH3g5/
结果如下:
-123 将转换为整数 0,
-10 将转换为整数 0,
-1 将转换为整数 0,
0 将转换为整数 1,
1 将转换为整数 0,
2 将转换为整数 0,
60 将转换为整数 0,
解决方案 2
正如 mblase75 所指出的,jAndy 有一些其他的解决方案可以和我一样:
v = +!v
它还首先从原始值生成布尔值,但使用 +
而不是 1*
将其转换为整数。结果完全相同,但符号更短。
解决方案 3
另一种方法是使用 ~~
运算符:
v = ~~!v
这是非常罕见的,并且总是从布尔值转换为整数。
+
以将其转换为数字,因此 +!v
等效于您的解决方案(OP 评论中的 jAndy 解决方案)。
1*
可以替换为 +
是对的。我的答案中的其他所有内容都保持不变。 jAndy 的回答是正确的,但我的回答更详细。我会将他/她的解决方案添加到我的答案中。
总结另一个答案,评论和我自己的观点,我建议将两件事结合起来:
使用切换函数在此函数内部使用更易读的实现
这是您可以放置在库中的函数,也可以将其包装在另一个 Javascript 框架的插件中。
function inv(i) {
if (i == 0) {
return 1
} else {
return 0;
}
}
用法很简单:
v = inv(v);
优点是:
无代码重复 如果您或任何人将来再次阅读此内容,您将在最短的时间内理解您的代码。
function toggle(i){ return i == 0 ? 1 : 0 }
?
这是缺少的:
v = [1, 0][v];
它也可以循环使用:
v = [2, 0, 1][v]; // 0 2 1 0 ...
v = [1, 2, 0][v]; // 0 1 2 0 ...
v = [1, 2, 3, 4, 5, 0][v]; // 0 1 2 3 4 5 ...
v = [5, 0, 1, 2, 3, 4][v]; // 0 5 4 3 2 1 0 ...
或者
v = {0: 1, 1: 0}[v];
最后一个解决方案的魅力,它也适用于所有其他值。
v = {777: 'seven', 'seven': 777}[v];
对于非常特殊的情况,例如获取(变化的)值和 undefined
,此模式可能会有所帮助:
v = { undefined: someValue }[v]; // undefined someValue undefined someValue undefined ...
v = 7
,那么对于 OP 的答案 v = (v == 0 ? 1 : 0)
,v 是 0。现在,对于 v = [1, 0][v]
,v 是未定义的。我想我在这里遗漏了一些东西。
v
并取 0
或 1
的值。
我不知道您为什么要构建自己的布尔值?我喜欢时髦的语法,但为什么不编写易于理解的代码呢?
这不是最短/最快的,但最清晰(并且对每个人都可读)是使用众所周知的 if/else 状态:
if (v === 0)
{
v = 1;
}
else
{
v = 0;
}
如果您想真正清楚,您应该为此使用布尔值而不是数字。对于大多数情况,它们足够快。使用布尔值,您可以只使用以下语法,这将在短期内获胜:
v = !v;
=== 0
。对于 7
的样本输入,正确的输出是 0
,但这将输出 1
。
您原始解决方案的另一种形式:
v = Number(v == 0);
编辑:感谢 TehShrike 和 Guffa 指出我原始解决方案中的错误。
'opacity:'+true
为例,您最终会得到 opacity:true
而不是 opacity:1
。
我会让它更明确。
v
是什么意思?
例如,当 v 是某个状态时。创建对象状态。在 DDD 中是一个值对象。
在这个值对象中实现逻辑。然后,您可以以更具可读性的功能性更强的方式编写代码。可以通过基于当前状态创建新状态来切换状态。然后将您的 if 语句/逻辑封装在您的对象中,您可以对其进行单元测试。 valueObject 始终是不可变的,因此它没有标识。所以为了改变它的价值,你必须创造一个新的。
例子:
public class Status
{
private readonly int _actualValue;
public Status(int value)
{
_actualValue = value;
}
public Status(Status status)
{
_actualValue = status._actualValue == 0 ? 1 : 0;
}
//some equals method to compare two Status objects
}
var status = new Status(0);
Status = new Status(status);
由于这是 JavaScript,我们可以使用一元 +
转换为 int:
v = +!v;
这将逻辑 NOT
v
的值(如果 v == 0
给出 true
,如果 v == 1
给出 false
)。然后我们将返回的布尔值转换为其对应的整数表示。
另一种方法:
v = ~(v|-v) >>> 31;
还有一个:v=++v%2
(在 C 中很简单 ++v%=2
)
附言。是的,我知道这是双重赋值,但这只是对 C 方法的原始重写(它不能按原样工作,因为 JS 预增量运算符不返回左值。
++
运算符的结果(它不是左值)。至于 v=++v%2
,您修改了 v
两次。我不知道这在 JavaScript 中是否定义得很好,但这不是必需的。 v = (v+1) % 2
。
c++
中是 - 因为预增量运算符具有更高的优先级并“就地”修改变量,所以它可以用作左值。我认为 ++
的 JS 实现不能被视为左值:/ 是的,这是多余的,但我试图展示另一种方法 - 已经发布了更好的解决方案 :)
如果您保证您的输入是 1 或 0,那么您可以使用:
v = 2+~v;
只是为了踢球:v = Math.pow(v-1,v)
也在 1 和 0 之间切换。
定义一个数组{1,0},将 v 设置为 v[v],因此值为 0 的 v 变为 1,反之亦然。
另一种创造性的做法,即 v
等于任何值,将始终返回 0
或 1
v = !!v^1;
!!
不会在逻辑数学中产生任何结果,您可以将 !!!!
放在那里并且会相同,但会产生 4 个不需要的操作
!!
将转换为布尔值。 !!(1) === true
和 !!(0) === false
v = Boolean(v^1)
会提供更多信息,感谢您的解释 - 没想过选角
!
会将其转换为布尔值。添加另一个 !
将否定该布尔值。强制转换在这里是隐式的,最终结果有效。不需要-1。
如果 v 的可能值只有 0 和 1,那么对于任何整数 x,表达式:v = Math.pow((Math.pow(x, v) - x), v);将切换值。
我知道这是一个丑陋的解决方案,并且 OP 并没有在寻找这个......但是当我在厕所时,我正在考虑另一种解决方案:P
未经测试,但如果您使用布尔值,我认为 var v = !v
会起作用。
参考:http://www.jackfranklin.co.uk/blog/2011/05/a-better-way-to-reverse-variables
v=!v;
适用于 v=0 和 v=1;并切换状态;
如果只有两个值,例如在这种情况下(0, 1),我认为使用 int 是浪费的。而是选择布尔值并按位工作。我知道我在假设,但如果在两种状态之间切换,布尔值似乎是理想的选择。
v = 数字(!v)
它将反转布尔值类型转换为数字,这是所需的输出。
好吧,正如我们所知,在 javascript 中,只有布尔比较也会给你预期的结果。
即 v = v == 0
就足够了。
下面是代码:
变量 v = 0; alert("如果 v 为 0 输出:" + (v == 0)); setTimeout(function() { v = 1; alert("如果 v 为 1 输出:" + (v == 0)); }, 1000);
JSFiddle:https://jsfiddle.net/vikash2402/83zf2zz0/
希望这会帮助你:)
true
和 false
之间切换。您可以使用 v == 0
来确定条件中变量的值,但如果您想使用值 0 或 1,则需要使用 v == 0 ? 0 : 1
或 Number(v)
之类的东西来获得它。 (此外,您可以使用 v = !v;
在 true
和 false
之间切换。)
不定期副业成功案例分享
v ^= 1
的人应该停止编程有点苛刻。如前所述,它不是更常见的运算符之一,它与v = v ^ 1
的作用不同。运算符在不同语言(VB)中的含义也完全不同。是的,快速查找会告诉你它是一个 XOR 运算符,你会明白它在做什么,但对许多人来说,乍一看可能并不明显。我不认为这意味着你需要辞职。