【问题标题】:How to test if a list contains consecutive integers in Mathematica?如何测试列表是否包含 Mathematica 中的连续整数?
【发布时间】:2011-10-28 15:56:31
【问题描述】:

我想测试一个列表是否包含连续的整数。

 consQ[a_] := Module[
  {ret = True}, 
  Do[If[i > 1 && a[[i]] != a[[i - 1]] + 1, ret = False; Break[]], {i, 
  1, Length[a]}]; ret]

虽然函数 consQ 可以完成这项工作,但我想知道是否有更好(更短、更快)的方法来执行此操作,最好使用函数式编程风格。

编辑: 上面的函数将具有递减顺序的连续整数的列表映射为 False。我想将其更改为 True。

【问题讨论】:

    标签: wolfram-mathematica


    【解决方案1】:

    Szablics 的解决方案可能是我会做的,但这里有一个替代方案:

    consQ[a : {___Integer}] := Most[a] + 1 === Rest[a]
    consQ[_] := False
    

    请注意,这些方法在处理空列表的方式上有所不同。

    【讨论】:

    • 还有1号的清单。我更喜欢你的。
    • 快速、实用且紧凑。 :-) 但是很神秘(对我来说),Union@Differences 接近于自我记录。 - 很难决定哪一个是最好的! - 两者都让我的“解决方案”远远落后于性能。
    • 但是很容易坏掉。设置a = {1,2,3,4,5} 并从那里开始。
    • 请查看 EDIT: 以及进一步的问题。你会如何修改你的 consQ?
    • @nilo,你可以跟随贝利撒留的领导并使用SignMost[a] + Sign[a[[2]]-a[[1]]] === Rest[a]
    【解决方案2】:

    你可以使用

    consQ[a_List ? (VectorQ[#, IntegerQ]&)] := Union@Differences[a] === {1}
    consQ[_] = False
    

    如果您知道传递给它的每个列表都只有整数,您可能希望删除整数测试。

    编辑:一点额外:如果您使用没有Differences 的非常旧的版本,或者想知道如何实现它,

    differences[a_List] := Rest[a] - Most[a]
    

    编辑 2: 请求的更改:

    consQ[a : {Integer___}] := MatchQ[Union@Differences[a], {1} | {-1} | {}]
    consQ[_] = False
    

    这适用于递增和递减序列,并为大小为 1 或 0 的列表提供 True

    更一般地,您可以使用equallySpacedQ[a_List] := Length@Union@Differences[a] == 1 之类的东西来测试数字列表是否等距

    【讨论】:

    • 由于您正在测试差异集完全 {1},因此检查列表是否包含一个整数就足够了,而不是检查所有整数。
    • 或者没有完整性约束: consQ[a_] := Union@Differences[a] === {1}。凉爽的。在您的解决方案和 Champion 的解决方案之间很难做出选择。 - (我不知道 Mathematica 有差异功能。)
    • 请查看 EDIT: 以及进一步的问题。你会如何修改你的 consQ?
    • 感谢您的编辑。 @Szabolcs - 我喜欢你的答案,因为它的可读性、紧凑性和功能风格,尽管从技术上讲它可能不是最快的。 - 解决方案的多样性展示了 Mathematica 的力量。
    【解决方案3】:

    我觉得下面的也很快,对比倒排的列表也不会花更长的时间:

    a = Range[10^7];
    f[a_] := Range[Sequence @@ ##, Sign[-#[[1]] + #[[2]]]] &@{a[[1]], a[[-1]]} == a;
    Timing[f[a]]
    b = Reverse@a;
    Timing[f[b]]
    

    编辑

    迄今为止最快的解决方案的简短测试:

    a = Range[2 10^7];
    Timing@consQSzab@a
    Timing@consQBret@a
    Timing@consQBeli@a
    (*
    {6.5,True}
    {0.703,True}
    {0.203,True}
    *)
    

    【讨论】:

    【解决方案4】:

    我喜欢其他两个的解决方案,但我会担心很长的列表。考虑数据

    d:dat[n_Integer?Positive]:= d = {1}~Join~Range[1, n]
    

    它在一开始就有它的非连续点。为 Brett's 设置 consQ1,为 Szabolcs 设置 consQ2,我明白了

    AbsoluteTiming[ #[dat[ 10000 ] ]& /@ {consQ1, consQ2}
    { {0.000110, False}, {0.001091, False} }
    

    或者,两者之间大约相差十倍,这与多次试验保持相对一致。这个时间可以通过使用NestWhile 短路进程来减少大约一半:

    Clear[consQ3]
    consQ3[a : {__Integer}] := 
     Module[{l = Length[a], i = 1},
       NestWhile[# + 1 &, i, 
          (#2 <= l) && a[[#1]] + 1 == a[[#2]] &, 
       2] > l
     ]
    

    测试每一对,只有当它们返回 true 时才会继续。时间安排

    AbsoluteTiming[consQ3[dat[ 10000 ]]]
    {0.000059, False}
    

    {0.000076, False}
    

    consQ。因此,Brett 的答案相当接近,但有时会花费两倍的时间。

    编辑:我将时序数据的图表移至Community Wiki answer

    【讨论】:

    • 我不是计时专家,但在比较秒算法速度时,不是计时功能要选择吗? - 我问是因为我在使用 Timing 而不是 AbsoluteTiming 时得到不同的结果。 - 我对哪种解决方案使用最快的算法感兴趣。
    • @niloderoock,我添加了计时数据,使用Timing 回答。
    • @belisarius,绝对的。给我几个小时。
    • @belisarius,我也是,见我的wiki answer
    【解决方案5】:

    Fold 可以用在一个运行速度非常快的相当简洁的表达式中:

    consQFold[a_] := (Fold[If[#2 == #1 + 1, #2, Return[False]] &, a[[1]]-1, a]; True)
    

    模式匹配可用于提供非常清晰的意图表达,但会显着降低性能:

    consQMatch[{___, i_, j_, ___}] /; j - i != 1 := False
    consQMatch[_] = True;
    

    编辑

    consQFold,如所写,在 Mathematica v8.0.4 中有效,但在 v8 或 v7 的早期版本中无效。为了纠正这个问题,有几个选择。首先是明确命名Return点:

    consQFold[a_] :=
      (Fold[If[#2==#1+1, #2, Return[False,CompoundExpression]] &, a[[1]]-1, a]; True)
    

    第二个,正如@Mr.Wizard 所建议的,将Return 替换为Throw / Catch

    consQFold[a_] :=
      Catch[Fold[If[#2 == #1 + 1, #2, Throw[False]]&, a[[1]]-1, a]; True]
    

    【讨论】:

    • 这是我在阅读问题时想到的,但您不是要使用Throw 而不是Return吗?
    • @Mr.Wizard Throw 也可以,但需要相应的Catch。因此,Return 更简洁,因为它退出了最近的封闭结构(在这种情况下,consQFold 的定义)。
    • @Mr.Wizard 啊哈!我现在看到了问题。 Return 似乎在版本 7 和版本 8.0.1 中被破坏。它在 8.0.4 版中再次修复(或损坏,取决于您的观点:)。
    • Return 在 8.0.4 中可以使用多少个构造?哦,当然,+1。
    • @Mr.Wizard 似乎有很多关于Return 的传说——而事实却很少。官方文档很少。例如,两个参数的形式是almost undocumented。我不止一次对记录在案的行为感到惊讶:如果省略 [第二个参数],则使用内置启发式方法确定受影响的函数或循环。我想我应该知道比依赖它更好,而且我有幸在闪亮的新 8.0.4 中尝试我的代码。
    【解决方案6】:

    因为时机似乎相当重要。我已将各种方法之间的比较移至此,Community Wiki,答案。

    使用的数据只是连续整数的列表,带有一个不连续的点,它们是通过生成的

    d : dat[n_Integer?Positive] := (d = {1}~Join~Range[1, n])
    d : dat[n_Integer?Positive, p_Integer?Positive] /; p <= n := 
         Range[1, p]~Join~{p}~Join~Range[p + 1, n]
    

    dat[n] 的第一种形式等同于dat[n, 1]。计时码很简单:

    Clear[consQTiming]
    Options[consQTiming] = {
       NonConsecutivePoints -> {10, 25, 50, 100, 250,500, 1000}};
    consQTiming[fcns__, OptionPattern[]]:=
    With[{rnd = RandomInteger[{1, #}, 100]}, 
      With[{fcn = #}, 
         Timing[ fcn[dat[10000, #]] & /@ rnd ][[1]]/100
      ] & /@ {fcns}
    ] & /@ OptionValue[NonConsecutivePoints]
    

    它会生成 100 个介于 1 和 {10, 25, 50, 100, 250, 500, 1000}dat 之间的随机整数,然后将这些随机数中的每一个用作 10,000 个元素长的列表中的非连续点。然后将每个consQ 实现应用于dat 生成的每个列表,并对结果进行平均。绘图功能很简单

    Clear[PlotConsQTimings]
    Options[PlotConsQTimings] = {
         NonConsecutivePoints -> {10, 25, 50, 100, 250, 500, 1000}};
    PlotConsQTimings[timings : { _?VectorQ ..}, OptionPattern[]] :=
      ListLogLogPlot[
        Thread[{OptionValue[NonConsecutivePoints], #}] & /@ Transpose[timings],
        Frame -> True, Joined -> True, PlotMarkers -> Automatic
      ]
    

    我为consQSzabolcs1consQSzabolcs2consQBrettconsQRCollyerconsQBelisariusconsQWRFoldconsQWRFoldconsQWRFold2consQWRFold3consQWRMatch 和@987654@3 的以下函数计时987654352@.

    从最左边的时序升序排列:consQBelisariusconsQWizardconsQRCollyerconsQBrettconsQSzabolcs1consQWRMatchconsQSzabolcs2consQWRFold2consQWRFold3和@ 987654362@.

    编辑:使用timeAvg(第二个)而不是consQTiming 中的Timing 重新运行所有函数。不过,我的平均跑步次数仍然超过 100 次。在大多数情况下,有任何变化,除了最低的两个在运行之间有一些变化。因此,请对这两行持保留态度,因为它们的时间实际上是相同的。

    【讨论】:

    • @belisarius,将其推出以允许随机不连续点到 5000 和 10000,并更新图片。
    • @belisarius,在你的正上方,低于你的 50 到 1000 之间。
    • 是的,但它是哪个函数?先生的回答有两个功能
    • @belisarius,我想我在文中已经说得很清楚了,显然不是。这是他的函数版本,f。我没有打扰另一个,因为 WReach 将该修复应用于consQWRFold3。所以,我很惊讶时间有什么不同。
    • 对不起,我没听懂。非常感谢!
    【解决方案7】:

    我现在确信 belisarius 正试图通过故意编写复杂的代码来得到我的山羊。 :-p

    我会写:f = Range[##, Sign[#2 - #]]&amp; @@ #[[{1, -1}]] == # &amp;

    另外,我相信 WReach 可能打算写如下内容:

    consQFold[a_] := 
     Catch[
      Fold[If[#2 === # + 1, #2, Throw@False] &, a[[1]] - 1, a]; 
      True
     ]
    

    【讨论】:

    • -14 用于对我的版权和混淆代码进行逆向工程
    • 有一款酒适合您的goat problem
    猜你喜欢
    • 1970-01-01
    • 2011-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-13
    • 1970-01-01
    • 2011-12-28
    • 2011-03-16
    相关资源
    最近更新 更多