重叠条带

时间:2011-04-25 22:38:01

标签: wolfram-mathematica

假设我有一系列沿着无限标尺放置的纸条,其中起点和终点由数字对指定。我想创建一个列表,表示沿标尺点的纸张层数。

例如:

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

最有效,最干净或简洁的方法是什么,适应真实和理性的剥离位置?

9 个答案:

答案 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}]

enter image description here

答案 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 -> "."]

screenshot of result

答案 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]

example output

对于1,000层和10,000点,预计算阶段可能需要相当长的时间,但单个点计算相对较快:

example output