编写一个函数,返回与(x,y)4向相邻的所有有效点的可迭代对象


17

通常,算法类和计算机科学中非常普遍的需求是在网格或矩阵上(例如在BFS或DFS中)对4方向进行迭代。这似乎经常导致大量笨拙和冗长的代码,并且在循环内进行了大量的算术和比较。我已经看到了许多不同的方法,但是我无法撼动这种简单的方法。

面临的挑战是编写一个纯函数,给定一个有限平面的宽度和高度,该平面n, m起源于point (0,0),并且坐标(x,y)可以表示该平面内的任何有效点,返回平面内所有点的4方向可迭代对象毗邻(x,y)

目的是在尽可能少的字节中定义该功能。

一些示例可帮助说明有效的输入/输出:

n = 5 (y-axis), m = 3 (x-axis) (zero-based)

matrix = [
    [A, B, C],
    [D, E, F],
    [G, H, I],
    [J, K, L],
    [M, N, O],
]

(x, y) => [valid iterable points]

E: (1, 1) => [(1, 0), (2, 1), (1, 2), (0, 1)]
A: (0, 0) => [(1, 0), (0, 1)]
L: (2, 3) => [(2, 2), (2, 4), (1, 3)]
N: (1, 4) => [(1, 3), (2, 4), (0, 4)]
n = 1 (y-axis), m = 1 (x-axis) (zero-based)

matrix = [
    [A],
]

(x, y) => [valid iterable points]

A: (0, 0) => []
n = 2 (y-axis), m = 1 (x-axis) (zero-based)

matrix = [
    [A],
    [B],
]

(x, y) => [valid iterable points]

A: (0, 0) => [(0, 1)]
B: (0, 1) => [(0, 0)]

这是一个满足条件的函数的示例(此示例在Python中):

def four_directions(x, y, n, m):
    valid_coordinates = []
    for xd, yd in [(1, 0), (0, 1), (-1, 0), (0, -1)]:
        nx, ny = x + xd, y + yd
        if 0 <= nx < m and 0 <= ny < n:
            valid_coordinates.append((nx, ny))
    return valid_coordinates

上面的示例定义了一个命名函数,但是匿名函数也是可以接受的。

输入n, m, x, y均为以下范围内的所有无符号32位整数:

n > 0
m > 0
0 <= x < m
0 <= y < n

输出必须采用(x,y)对的可迭代形式(但是您选择的语言定义了该形式)。

其他说明:

只要可迭代对象的使用者可以访问x并且y整数只能知道其位置,复数(以及其他表示形式/序列化)就可以。

基于非零的索引是可接受的,但前提是所选择的语言是非零索引的语言。如果语言使用多种编号系统,则默认使用最常用于表示矩阵的数据结构的编号系统。如果这些仍然是给定语言中的所有外来概念,则任何起始索引都是可以接受的。


6
欢迎光临本站!从我们的标准来看,这个挑战相当不错,但是这里有些事情与我们的风格背道而驰。对于一个人,我们更喜欢挑战,如果可能的话,挑战不限于一种语言。每个人都可以竞争时,这会更加有趣。通常,我们也以字节单位而不是字符来对代码高尔夫球评分,在大多数情况下,它们都是相同的,但是如果用字符对答案进行评分,则可以做一些欺骗性的事情。希望你在这里玩得开心!
发布Rock Garf Hunter

我们保证(x,y)自己在矩形中,对吗?
xnor19年

4
默认情况下,CGCC允许完整的程序以及功能作为提交。这有助于使不一定具有功能概念的语言也能竞争
Jo King

3
输出将输出到STDOUT,而不是代码对象。通常可以是带有清晰分隔符的任何输出,因此它是明确的,并且遵循默认的标准输出格式
Jo King

2
是否允许将坐标表示为复数而不是整数元组?
乔尔

Answers:


12

Python 2,66个字节

lambda m,n,x,y:[(x-1,y),(x+1,y)][~x:m-x]+[(x,y-1),(x,y+1)][~y:n-y]

在线尝试!

列出四个邻居,然后使用列表切片来删除超出范围的邻居。


Python 2,71个字节

lambda m,n,x,y:[(k/n,k%n)for k in range(m*n)if(k/n-x)**2+(k%n-y)**2==1]

在线尝试!

而不是检查四个邻居中的哪个是入站的,而是采用一种较慢的方法来检查所有邻居的入站点,即它们与的欧几里得距离恰好为(x,y)。我们还使用经典的div-mod技巧在网格上进行迭代,从而省去了编写两个循环的需要for i in range(m)for j in range(n)

我尝试使用复杂的算术来写距离条件,但结果却写了更长的时间abs((k/n-x)*1j+k%n-y)==1


Python 2 2,70个字节

lambda m,n,x,y:[(x+t/3,y+t%3-1)for t in-2,0,2,4if m>x+t/3>=0<y+t%3<=n]

在线尝试!


11
恭喜!
Arnauld

4

八度,90字节

这使用一种几何方法:首先,我们创建所需大小的零矩阵,然后将a设置1为所需位置。然后我们与内核进行卷积

[0, 1, 0]
[1, 0, 1]
[0, 1, 0]

它会产生一个与原始点的4个邻居相同大小的新矩阵。然后,我们find()对该新矩阵的非零项的索引进行索引。

function [i,j]=f(s,a,b);z=zeros(s);z(a,b)=1;[i,j]=find(conv2(z,(v=[1;-1;1])*v'<0,'same'));

在线尝试!

卷积是成功的关键。


4
的确,无论字体多么小,它都是
Luis Mendo


3

JavaScript(ES6),74个字节

无聊的方法。

(h,w,x,y)=>[x&&[x-1,y],~x+w&&[x+1,y],y&&[x,y-1],++y-h&&[x,y]].filter(_=>_)

在线尝试!


JavaScript(Node.js),74字节

少点无聊,但就那样长。将输入作为([h,w,x,y])

a=>a.flatMap((_,d,[h,w,x,y])=>~(x+=--d%2)*~(y+=--d%2)&&x<w&y<h?[[x,y]]:[])

在线尝试!


JavaScript(V8),67字节

如果所有标准输出方法都允许,我们可以使用以下命令打印有效坐标:

(h,w,x,y)=>{for(;h--;)for(X=w;X--;)(x-X)**2+(y-h)**2^1||print(X,h)}

在线尝试!


2

果冻 13  12 字节

2ḶṚƬNƬẎ+⁸%ƑƇ

双向链接,在左侧接受两个(0索引)整数的列表,[row, column]在右侧接受两个整数[height, width]的列表,这产生一个整数列表的列表[[adjacent_row_1, adjacent_column_1], ...]

在线尝试!

怎么样?

2ḶṚƬNƬẎ+⁸%ƑƇ - Link: [row, column]; [height, width]   e.g. [3,2]; [5,3] (the "L" example)
2            - literal 2                                   2
 Ḷ           - lowered range                               [0,1]
   Ƭ         - collect up while distinct, applying:
  Ṛ          -   reverse                                   [[0,1],[1,0]]
     Ƭ       - collect up while distinct, applying:
    N        -   negate                                    [[[0,1],[1,0]],[[0,-1],[-1,0]]]
      Ẏ      - tighten                                     [[0,1],[1,0],[0,-1],[-1,0]]
        ⁸    - chain's left argument ([row, column])       [3,2]
       +     - add (vectorises)                            [[3,3],[4,2],[3,1],[2,2]]
           Ƈ - filter keep if:
          Ƒ  -   is invariant under:
         %   -     modulo ([height, width]) (vectorises)    [3,0] [4,2] [3,1] [2,2]
             - (...and [3,0] is not equal to [3,3] so ->)  [[4,2],[3,1],[2,2]]

您可以替换ḶṚƬṬ€2ḶṚƬNƬẎreturn [[0, 1], [1, 0], [0, -1], [-1, 0]],而2Ṭ€NƬẎreturn [[1], [0, 1], [-1], [0, -1]]和,并且由于单例被包装,因此+仅使用的第一个元素进行矢量化,因此它们的行为就好像它们的第二个元素是0(可加性)。结果,只有输出的顺序可以改变。
Erik the Outgolfer

2

Perl 6 56个 49字节

-7个字节感谢nwellnhof!

{grep 1>(*.reals Z/@^b).all>=0,($^a X+1,-1,i,-i)}

在线尝试!

通过检查是否除以数组范围是否在0到1之间,来删除超出范围的元素。通过复数进行输入和输出,其中实数部分是x坐标,而虚数是y。您可以通过.im.re函数提取它们。



@nwellnhof非常好!我想建立在它做像这样,但div似乎并没有工作Num小号
乔金

(*.reals>>.Int Zdiv@^b).none(*.reals Z/@^b)>>.Int.none可以使用,但是Int-cast似乎太昂贵了。
nwellnhof

1

J30 29 28字节

(([+.@#~&,1=|@-)j./)~j./&i./

在线尝试!

怎么样:

  • 向右转mxn arg变成复数网格j./&i./
  • 左arg(我们的点)相同 j./
  • 创建一个遮罩,以显示我们的点与网格之间的距离正好为1的位置 1=|@-
  • 在将两个平面都展平后,使用它来过滤网格 #~&,
  • 将结果转回真实点 +.@


0

木炭,29字节

Jθη#FIζFIε«Jικ¿№KV#⊞υ⟦ικ⟧»⎚Iυ

在线尝试!链接是详细版本的代码。以x,y,宽度,高度的顺序输入。说明:

Jθη#

#在提供的位置打印。

FIζFIε«

在给定的矩形上循环。

Jικ

跳转到当前位置。

¿№KV#⊞υ⟦ικ⟧

如果有相邻#位置,则保存位置。

»⎚Iυ

在循环末尾输出发现的位置。

无聊的答案:

FIζFIε¿⁼¹⁺↔⁻ιIθ↔⁻κIηI⟦ικ

在线尝试!链接是详细版本的代码。通过数学计算相邻位置来工作。


0

Haskell,62个字节

使用 圆方程

f m n a b = [(x,y)|x<-[0..m-1],y<-[0..n-1],(x-a)^2+(y-b)^2==1]

在线尝试!

无聊的方法:81个字节

f m n x y=filter (\(x,y)->x>=0&&y>=0&&x<m&&y<n) [(x-1,y),(x+1,y),(x,y-1),(x,y+1)]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.