假设我有一系列沿着无限标尺放置的纸条,其中起点和终点由数字对指定。我想创建一个列表,表示沿标尺点的纸张层数。
例如:
strips =
{{-27, 20},
{ -2, -1},
{-47, -28},
{-41, 32},
{ 22, 31},
{ 2, 37},
{-28, 30},
{ -7, 39}}
应输出:
-47 -41 -27 -7 -2 -1 2 20 22 30 31 32 37 39
1 2 3 4 5 4 5 4 5 4 3 2 1 0
最有效,最干净或简洁的方法是什么,适应真实和理性的剥离位置?
答案 0 :(得分:5)
这是一种方法:
Clear[hasPaper,nStrips]
hasPaper[y_, z_] := Piecewise[{{1, x <= z && x >= y}}, 0];
nStrips[y_, strip___] := Total@(hasPaper @@@ strip) /. x -> y
您可以获得任意值的条带数量。
Table[nStrips[i, strips], {i, Sort@Flatten@strips}]
{1, 2, 3, 3, 3, 4, 5, 5, 5, 5, 5, 5, 4, 3, 2, 1}
另外,绘制它
Plot[nStrips[x, strips], {x, Min@Flatten@strips, Max@Flatten@strips}]
答案 1 :(得分:4)
这是一个解决方案:
In[305]:=
strips = {{-27, 20}, {-2, -1}, {-47, -28}, {-41, 32}, {22, 31}, {2,
37}, {-28, 30}, {-7, 39}};
In[313]:= int = Interval /@ strips;
In[317]:= Thread[{Union[Flatten[strips]],
Join[Count[int, x_ /; IntervalMemberQ[x, #]] & /@ (Mean /@
Partition[Union[Flatten[strips]], 2, 1]), {0}]}]
Out[317]= {{-47, 1}, {-41, 2}, {-28, 2}, {-27, 3}, {-7, 4}, {-2,
5}, {-1, 4}, {2, 5}, {20, 4}, {22, 5}, {30, 4}, {31, 3}, {32,
2}, {37, 1}, {39, 0}}
<小时/> 编辑使用
SplitBy
并对后续代码进行后处理可获得最短列表:
In[329]:=
strips = {{-27, 20}, {-2, -1}, {-47, -28}, {-41, 32}, {22, 31}, {2,
37}, {-28, 30}, {-7, 39}};
In[330]:= int = Interval /@ strips;
In[339]:=
SplitBy[Thread[{Union[Flatten[strips]],
Join[Count[int, x_ /; IntervalMemberQ[x, #]] & /@ (Mean /@
Partition[Union[Flatten[strips]], 2, 1]), {0}]}],
Last] /. {b : {{_, co_} ..} :> First[b]}
Out[339]= {{-47, 1}, {-41, 2}, {-27, 3}, {-7, 4}, {-2, 5}, {-1,
4}, {2, 5}, {20, 4}, {22, 5}, {30, 4}, {31, 3}, {32, 2}, {37,
1}, {39, 0}}
答案 2 :(得分:4)
你可能认为这是一种愚蠢的做法,但无论如何我都会提供它:
f[x_]:=Sum[UnitStep[x-strips[[k,1]]]-UnitStep[x-strips[[k,2]]],{k,Length[strips]}]
f/@Union[Flatten[strips]]
答案 3 :(得分:4)
f[u_, s_] := Total[Piecewise@{{1, #1 <= x < #2}} & @@@ s /. x -> u]
用法
f[#, strips] & /@ {-47, -41, -27, -7, -2, -1, 2, 20, 22, 30, 31, 32, 37, 39}
- &GT;
{1, 2, 3, 4, 5, 4, 5, 4, 5, 4, 3, 2, 1, 0}
对于开放/结束,只需使用&lt; = 或&lt;
答案 4 :(得分:2)
这是我的方法,类似于belisarius':
strips = {{-27, 20}, {-2, -1}, {-47, -28}, {-41, 32}, {22, 31}, {2,
37}, {-28, 30}, {-7, 39}};
pw = PiecewiseExpand[Total[Boole[# <= x < #2] & @@@ strips]]
Grid[Transpose[
SplitBy[SortBy[Table[{x, pw}, {x, Flatten[strips]}], First],
Last][[All, 1]]], Alignment -> "."]
答案 5 :(得分:1)
这是我的尝试 - 它适用于整数,有理数和实数,但并没有声称效率非常高。 (我犯了与Sasha相同的错误,我的原始版本没有返回最短的列表。所以我偷了SplitBy
修复!)
layers[strips_?MatrixQ] := Module[{equals, points},
points = Union@Flatten@strips;
equals = Function[x, Evaluate[(#1 <= x < #2) & @@@ strips]];
points = {points, Total /@ Boole /@ equals /@ points}\[Transpose];
SplitBy[points, Last] /. {b:{{_, co_}..} :> First[b]}]
strips = {{-27, 20}, {-2, -1}, {-47, -28}, {-41, 32}, {22, 31},
{2, 37}, {-28, 30}, {-7, 39}};
In[3]:= layers[strips]
Out[3]= {{-47, 1}, {-41, 2}, {-27, 3}, {-7, 4}, {-2, 5}, {-1, 4}, {2, 5},
{20, 4}, {22, 5}, {30, 4}, {31, 3}, {32, 2}, {37, 1}, {39, 0}}
In[4]:= layers[strips/2]
Out[4]:= {{-(47/2), 1}, {-(41/2), 2}, {-(27/2), 3}, {-(7/2), 4},
{-1, 5}, {-(1/2), 4}, {1, 5}, {10, 4}, {11, 5}, {15, 4}, {31/2, 3},
{16, 2}, {37/2, 1}, {39/2, 0}}
In[5]:= layers[strips/3.]
Out[5]= {{-15.6667, 1}, {-13.6667, 2}, {-9., 3}, {-2.33333, 4}, {-0.666667, 5},
{-0.333333, 4}, {0.666667, 5}, {6.66667, 4}, {7.33333, 5}, {10.,4},
{10.3333, 3}, {10.6667, 2}, {12.3333, 1}, {13., 0}}
答案 6 :(得分:1)
拼接在一起的邻接条带,确定层数的关键点 更改,并计算每个关键点栖息的条带数量:
splice[s_, {}] := s
splice[s_, vals_] := Module[{h = First[vals]},
splice[(s /. {{x___, {k_, h}, w___, {h, j_}, z___} :> {x, {k, j},
w, z}, {x___, {k_, h}, w___, {h, j_}, z___} :> {x, {k, j}, w,
z}}), Rest[vals]]]
splicedStrips = splice[strips, Union@Flatten@strips];
keyPoints = Union@Flatten@splicedStrips;
({#, Total@(splicedStrips /. {a_, b_} :> Boole[a <= # < b])} & /@ keyPoints)
// Transpose // TableForm
<小时/> 的修改
经过一段时间的努力,我能够删除splice
并更直接地删除不需要检查的点数(-28,在我们一直使用的strips
数据中):
keyPoints = Complement[pts = Union@Flatten@strips,
Cases[pts, x_ /; MemberQ[strips, {x, _}] && MemberQ[strips, {_, x}]]];
({#, Total@(strips /. {a_, b_} :> Boole[a <= # < b])} & /@ keyPoints)
答案 7 :(得分:1)
解决此问题的一种方法是转换条带
strips = {{-27, 20}, {-2, -1}, {-47, -28}, {-41, 32}
,{ 22, 31}, { 2, 37}, {-28, 30}, {-7, 39}}
到分隔符列表,标记条带的开头或结尾并按位置对其进行排序
StripToLimiters[{start_, end_}] := Sequence[BeginStrip[start], EndStrip[end]]
limiterlist = SortBy[StripToLimiters /@ strips, First]
现在我们可以将排序的限制器映射到递增/递减
LimiterToDiff[BeginStrip[_]] := 1
LimiterToDiff[EndStrip[_]] := -1
并使用Accumulate获取相交条带的中间总数:
In[6]:= Transpose[{First/@#,Accumulate[LimiterToDiff/@#]}]&[limiterlist]
Out[6]= {{-47,1},{-41,2},{-28,3},{-28,2},{-27,3},{-7,4},{-2,5},{-1,4}
,{2,5},{20,4},{22,5},{30,4},{31,3},{32,2},{37,1},{39,0}}
或没有中间limiterlist
:
In[7]:= StripListToCountList[strips_]:=
Transpose[{First/@#,Accumulate[LimiterToDiff/@#]}]&[
SortBy[StripToLimiters/@strips,First]
]
StripListToCountList[strips]
Out[8]= {{-47,1},{-41,2},{-28,3},{-28,2},{-27,3},{-7,4},{-2,5},{-1,4}
,{2,5},{20,4},{22,5},{30,4},{31,3},{32,2},{37,1},{39,0}}
答案 8 :(得分:0)
以下解决方案假定层计数功能将被多次调用。它使用了层预计算和Nearest
,以便大大减少在任何给定点计算图层数所需的时间:
layers[strips:{__}] :=
Module[{pred, changes, count}
, changes = Union @ Flatten @ strips /. {c_, r___} :> {c-1, c, r}
; Evaluate[pred /@ changes] = {changes[[1]]} ~Join~ Drop[changes, -1]
; Do[count[x] = Total[(Boole[#[[1]] <= x < #[[2]]]) & /@ strips], {x, changes}]
; With[{n = Nearest[changes]}
, (n[#] /. {m_, ___} :> count[If[m > #, pred[m], m]])&
]
]
以下示例使用layers
定义一个新函数f
,它将计算所提供样本条的图层数:
$strips={{-27,20},{-2,-1},{-47,-28},{-41,32},{22,31},{2,37},{-28,30},{-7,39}};
f = layers[$strips];
f
现在可用于计算某一点的图层数量:
Union @ Flatten @ $strips /. s_ :> {s, f /@ s} // TableForm
Plot[f[x], {x, -50, 50}, PlotPoints -> 1000]
对于1,000层和10,000点,预计算阶段可能需要相当长的时间,但单个点计算相对较快: