如何测试列表是否包含Mathematica中的连续整数?

时间:2011-10-28 15:56:32

标签: wolfram-mathematica

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

 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。

7 个答案:

答案 0 :(得分:11)

Szablics的解决方案可能就是我所做的,但这里有另一种选择:

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

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

答案 1 :(得分:9)

您可以使用

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}}提供大小为1或0的列表。

更一般地说,您可以测试数字列表是否与True

等间隔相等

答案 2 :(得分:8)

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

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。所以,布雷特的答案相当接近,但偶尔也需要两倍的时间。

修改:我将时间数据的图表移到Community Wiki answer

答案 3 :(得分:8)

我认为以下内容也很快,并且比较反向列表不会花费更长时间:

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 :(得分: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]

答案 5 :(得分:5)

我现在确信belisarius试图通过编写故意复杂的代码来获取我的山羊。 :-P

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

另外,我认为WReach可能会写一些类似的东西:

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

答案 6 :(得分:5)

因为时机似乎相当重要。我已经将各种方法之间的比较,社区维基,回答。

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

生成的
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]

它在{10, 25, 50, 100, 250, 500, 1000}dat之间生成100个随机整数,然后使用每个随机数作为列表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
  ]

timing data for various functions

我计划了以下功能consQSzabolcs1consQSzabolcs2consQBrettconsQRCollyerconsQBelisariusconsQWRFoldconsQWRFold2consQBelisarius的{​​{3}},consQWRFold3consQWRMatch

按最左侧时间的升序排列:consQBelisariusconsQWizardconsQRCollyerconsQBrettconsQSzabolcs1consQWRMatch,{{ 1}},consQSzabolcs2consQWRFold2consQWRFold3

修改:重新使用MrWizard's version(第二个)的所有功能,而不是consQWRFold中的Timing。不过,我的平均成绩仍超过100次。在大多数情况下,有任何变化,除了最低的两个,其中从运行到运行有一些变化。所以,把这两条线带上一粒盐,因为它们的时间几乎相同。

enter image description here