【问题标题】:How do I create larger polygons out of a smaller polygons如何从较小的多边形中创建较大的多边形
【发布时间】:2018-04-20 13:49:09
【问题描述】:

我想转换以下多边形列表:

[
  %{height: 32, width: 32, x: 0, y: 0},
  %{height: 32, width: 32, x: 32, y: 0},
  %{height: 32, width: 32, x: 64, y: 0},
  %{height: 32, width: 32, x: 256, y: 0},
  %{height: 32, width: 32, x: 288, y: 0}
]

进入相邻多边形连接的列表,如下所示:

[
  %{height: 32, width: 96, x: 0, y: 0},
  %{height: 32, width: 64, x: 256, y: 0}
]

我尝试使用 Enum.reduce_while 如下:

Enum.reduce_while(polys, 0, fn poly, max_x ->
  if poly.x - max_x <= 32, do: {:cont, max_x + 32}, else: {:halt, max_x}
end)

这可以给我第一个多边形,但是我如何获得后续的多边形,是否有可能一次性获得所有这些多边形?

【问题讨论】:

  • 第二个和第三个多边形是否被认为是相邻的?他们的x64 隔开,但宽度/高度只有32。
  • 感谢@Dogbert 指出这个错误。我已经编辑了我的问题。唯一的间隙应该在第三个和第四个多边形之间。

标签: functional-programming elixir


【解决方案1】:

这将是Enum.chunk_while/4 的完美用例:

input = [
  %{height: 32, width: 32, x: 0, y: 0},
  %{height: 32, width: 32, x: 32, y: 0},
  %{height: 32, width: 32, x: 64, y: 0},
  %{height: 32, width: 32, x: 256, y: 0},
  %{height: 32, width: 32, x: 288, y: 0}
]

chunk_fun = fn
  i, [] -> {:cont, i}
  %{width: iw, x: ix}, %{height: ah, width: aw, x: ax, y: ay}
       when ax + aw == ix ->
    {:cont, %{height: ah, width: aw + iw, x: ax, y: ay}}
  %{height: ih, y: iy}, %{height: ah, width: aw, x: ax, y: ay}
       when ay + ah == iy ->
    {:cont, %{height: ah + ih, width: aw, x: ax, y: ay}}
  i, acc -> {:cont, acc, i}
end

after_fun = fn
  [] -> {:cont, []}
  acc -> {:cont, acc, []}
end

input
|> Enum.chunk_while([], chunk_fun, after_fun)
|> IO.inspect()

#⇒ [%{height: 32, width: 96, x: 0, y: 0},
#   %{height: 32, width: 64, x: 256, y: 0}]

请注意,上面的示例还处理 y 轴连接。由于不寻常地将地图实例用作累加器,因此该示例很有趣。

【讨论】:

【解决方案2】:

我会在这里使用Enum.reduceEnum.reduce_while 适用于您希望根据某些条件进一步停止处理列表的情况。在这种情况下,您确实希望处理整个列表。

我所做的是在累加器中收集多边形,从只有第一个多边形的列表开始。然后,在每次缩减中,我检查前一个多边形的x + width 是否与新多边形的x 相同。如果是,我通过添加宽度来合并多边形,如果不是,我预先添加多边形。

列表是反向收集的,所以我在减少后使用Enum.reverse

[
  %{height: 32, width: 32, x: 0, y: 0},
  %{height: 32, width: 32, x: 32, y: 0},
  %{height: 32, width: 32, x: 64, y: 0},
  %{height: 32, width: 32, x: 256, y: 0},
  %{height: 32, width: 32, x: 288, y: 0}
]
|> Enum.reduce(nil, fn
  x, nil ->
    [x]

  x, [h | t] ->
    if h.x + h.width == x.x do
      [%{h | width: x.width + h.width} | t]
    else
      [x, h | t]
    end
end)
|> Enum.reverse()
|> IO.inspect()

输出:

[%{height: 32, width: 96, x: 0, y: 0}, %{height: 32, width: 64, x: 256, y: 0}]

【讨论】:

  • Enum.chink_while/4 在这里对我来说看起来更惯用。
  • 谢谢,使用 reduce 绝对是一个好方法,但我无法让它工作。
  • @Catharz 这有点不公平;此代码非常适用于您提供的示例数据。
  • 感谢@mudasobwa 指出这一点。我重试了这个解决方案,它按照要求工作。我没有让它工作不是这个答案的问题。我试图在 iex 中使用它是一个问题。我对这两个答案都投了赞成票。
猜你喜欢
  • 1970-01-01
  • 2012-01-19
  • 2012-06-11
  • 2013-06-25
  • 1970-01-01
  • 1970-01-01
  • 2013-12-11
  • 2021-11-08
  • 2018-06-13
相关资源
最近更新 更多