我想测试一个列表是否包含连续的整数。
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。
答案 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
]
我计划了以下功能consQSzabolcs1
,consQSzabolcs2
,consQBrett
,consQRCollyer
,consQBelisarius
,consQWRFold
,consQWRFold2
, consQBelisarius
的{{3}},consQWRFold3
和consQWRMatch
。
按最左侧时间的升序排列:consQBelisarius
,consQWizard
,consQRCollyer
,consQBrett
,consQSzabolcs1
,consQWRMatch
,{{ 1}},consQSzabolcs2
,consQWRFold2
和consQWRFold3
。
修改:重新使用MrWizard's version(第二个)的所有功能,而不是consQWRFold
中的Timing
。不过,我的平均成绩仍超过100次。在大多数情况下,有任何变化,除了最低的两个,其中从运行到运行有一些变化。所以,把这两条线带上一粒盐,因为它们的时间几乎相同。