多维逆转


23

给定非负整数的N维正交(无参)数组,并指示要反转的维数,则返回该数组,但沿这些维数反转。该指示可以作为长度为N的布尔列表或从0或1索引的前N个维度的子集的列表给出。

请说明您的输入格式。代码说明深表感谢。

演练示例

我们得到了2层3行4列3D阵列

[[[ 1, 2, 3, 4],
  [ 5, 6, 7, 8],
  [ 9,10,11,12]],

 [[13,14,15,16],
  [17,18,19,20],
  [21,22,23,24]]]

和其中之一

[true,false,true](布尔列表)
[0,2](0索引列表)
[1,3](1索引列表)

我们需要颠倒第一个和最后一个维度的顺序,即颠倒层和行(列)的元素,而不是每一层的行。首先(执行此操作的实际顺序无关紧要),我们颠倒了图层的顺序:

[[[13,14,15,16],
  [17,18,19,20],
  [21,22,23,24]],

 [[ 1, 2, 3, 4],
  [ 5, 6, 7, 8],
  [ 9,10,11,12]]]

然后我们反转每一行元素的顺序:

[[[16,15,14,13],
  [20,19,18,17],
  [24,23,22,21]],

 [[ 4, 3, 2, 1],
  [ 8, 7, 6, 5],
  [12,11,10, 9]]]

测试用例

[[[1,2,3,4],[5,6,7,8],[9,10,11,12]],[[13,14,15,16],[17,18,19,20],[21,22,23,24]]]
[true,false,true]/ [0,2]/ [1,3]
 ↓ 
[[[16,15,14,13],[20,19,18,17],[24,23,22,21]],[[4,3,2,1],[8,7,6,5],[12,11,10,9]]]


[[1,2,3],[4,5,6]]
[true,false]/ [0]/ [1]
 ↓
[[4,5,6],[1,2,3]]


[[1],[4]]
[true,false]/ [0]/ [1]
 ↓
[[4],[1]]


[[7]]
[true,true]/ [0,1]/ [1,2]
 ↓
[[7]]


[1,2,3,4,5,6,7]
[true]/ [0]/ [1]
 ↓
[7,6,5,4,3,2,1]


[]
[true]/ [0]/ [1]
 ↓
[]


[[],[]]
[false,false]/ []/ []
 ↓
[[],[]]


[[[[3,1,4,1],[5,9,2,6]],[[5,3,5,8],[9,7,9,3]]],[[[2,3,8,4],[6,2,6,4]],[[3,3,8,3],[2,7,9,5]]]]
[true,false,true,true]/ [0,2,3]/ [1,3,4]
 ↓
[[[[4,6,2,6],[4,8,3,2]],[[5,9,7,2],[3,8,3,3]]],[[[6,2,9,5],[1,4,1,3]],[[3,9,7,9],[8,5,3,5]]]]


[[[[3,1,4,1],[5,9,2,6]],[[5,3,5,8],[9,7,9,3]]],[[[2,3,8,4],[6,2,6,4]],[[3,3,8,3],[2,7,9,5]]]]
[false,true,false,false]/ [1]/ [2]
 ↓
[[[[5,3,5,8],[9,7,9,3]],[[3,1,4,1],[5,9,2,6]]],[[[3,3,8,3],[2,7,9,5]],[[2,3,8,4],[6,2,6,4]]]]


[[[[3,1,4,1],[5,9,2,6]],[[5,3,5,8],[9,7,9,3]]],[[[2,3,8,4],[6,2,6,4]],[[3,3,8,3],[2,7,9,5]]]]
[false,false,false,false]/ []/ []
 ↓
[[[[3,1,4,1],[5,9,2,6]],[[5,3,5,8],[9,7,9,3]]],[[[2,3,8,4],[6,2,6,4]],[[3,3,8,3],[2,7,9,5]]]]


我觉得大多数静态类型语言中最难的部分是打入所涉及的类型签名。
世纪

这些语言通常如何处理任意数组数据?
亚当

1
在我看来,有三种“正常”使用的情况:仅担心数组的一个级别(例如:reverse可在任意数组上使用,但仅关心第一级别),泛型或递归类(类型/对象类取决于函数)或OOP,但用例相似)。后两者通常更为冗长。
世纪

我们是否可以将矩阵存储为指向指针的数组(用C或asm表示),而不是存储所有相邻的适当的多维数组?我敢肯定,所有带有列表的任意嵌套的普通高级语言/动态类型的语言都已经将其视为列表的列表,而不是矩阵的列表,因此,我认为这很好。
彼得·科德斯

@PeterCordes当然,继续。
亚当

Answers:


8

APL(Dyalog)20 9字节

⊃{⌽[⍺]⍵}/

在线尝试!

怎么样?

/ -reduce-将输入中最右边的元素(数组)作为参数,然后将函数与下一个左元素作为左参数一起应用

{⌽[⍺]⍵}- left argument)维度相反

-展平封闭的数组



8

JavaScript(Node.js)58 55 53 45字节

@Shaggy节省了8个字节

将输入作为(indications)(array),其中指示是布尔列表。

f=([r,...b])=>a=>1/r?a.sort(_=>r).map(f(b)):a

在线尝试!

已评论

f = (                // f is a function taking:
  [r,                //   r = next 'reverse' Boolean flag
      ...b]          //   b = array of remaining flags
) =>                 // and returning an anonymous function taking:
  a =>               //   a = array (or sub-array) to process, or atomic element
    1 / r ?          // if r is defined:
      a.sort(_ => r) //   reverse a if r = 1; leave it unchanged otherwise
      .map(f(b))     //   for each element in the resulting array: do a recursive call,
                     //   using f to generate a new callback function for the next flag
    :                // else:
      a              //   a must be an atomic element and is simply left unchanged

只是使用r代替r||-1 似乎是可行的
毛茸茸的

f=([r,...b])=>a=>1/r?a.sort(_=>r).map(f(b)):a工作吗?在我的手机上无法正常测试。
毛茸茸的

@蓬松的尼斯!我喜欢这种异常的处理流程。
Arnauld


5

果冻,8字节

”€ẋ”ṚpFv

取得0索引的尺寸列表。

在线尝试!

怎么运行的

”€ẋ”ṚpFv  Main link. Left arg: D (dimensions, 0-based), Right arg: A (array)

”€ẋ       Repeat '€' d times, for each d in D.
   ”Ṛp    Perform Cartesian product of ['Ṛ'] and each string of '€'s, prepending a
          'Ṛ' to each string of '€'s.
      F   Flatten the result.
          If, e.g., D = [0,2,4], we build the string "ṚṚ€€Ṛ€€€€".
       v  Eval the resulting string, using A as left argument.

1
那太糟了。非常好!
亚当

5

R80 78 77字节

[通过创建一个在所示位置颠倒的序列列表来创建对R提取器的调用。它们实际上包含零,这些零会被静默忽略。该drop=F是需要防止的r维的默认丢弃。我们需要rev由于R填充数组的方式,调用维度反向指示器。

-2感谢@Giuseppe

-1使用串联分配。

function(x,a,d=dim(x))do.call("[",c(list(x),Map(seq,r<-d*rev(a),d-r),drop=F))

在线尝试!

值得一提的是@JayCe,他提出了一种变体,可以在相同的长度下获得相同的结果:

function(x,a,d=dim(x))array(x[t(t(expand.grid(Map(seq,r<-d*rev(a),d-r))))],d)

在线尝试!


1
78个字节非常不错的答案!
朱塞佩

1
非常深刻的答案。我花了一段时间才完全理解它。我尝试不使用而复制它do.call-它的长度更长,为83个字节,仍在此处作为参考注释发布:TIO
JayCe

好吧,@ JayCe,您的最佳答案也可以包含78个字节!
J.Doe

5

哈斯克尔120 119个字节

函数f将N维列表和bool列表作为输入

class F r where f::[Bool]->r->r
instance F Int where f=seq
instance F r=>F[r]where f(a:y)=last(id:[reverse|a]).map(f y)

1
您不需要括号F r
与Orjan约翰森

1
TIO与测试用例和OJ的1字节高尔夫链接。
Khuldraeseth na'Barya

4

05AB1E23 11 10 字节

'€s×'R«J.V

在线尝试。

-12个字节,感谢@ Mr.Xcoder

输入为0索引真值(即[0,2,3]),这是第一个输入。

说明:

'€s×           # Repeat "€" the indices amount of times
               #  i.e. [0,2,3] → ["","€€","€€€"]
    'R«        # Append each with "R"
               #  i.e. ["","€€","€€€"] → ["R","€€R","€€€R"]
        J      # Join them all together
               #  i.e. ["R","€€R","€€€R"] → R€€R€€€R
         .V    # Execute string as 05AB1E code

例如:如果索引input-list为[0,2,3],它将创建以下字符串:

R€€R€€€R

这将:

    €€€R    # Reverse the items in the most inner (4th level) lists
 €€R        # Reverse the most inner (3rd level) lists themselves
            # Do nothing with the inner (2nd level) lists 
R           # Reverse the entire outer (1st level) list

原始的23个字节的答案:

ćURvy„ RèJ…εÿ}}„ RXèJ.V

输入为布尔列表(即[1,0,1,1]),这是第一个输入。

在线尝试。

说明:

ćU                 # Pop and save the first boolean in variable `X`
  R                # Reverse the remaining boolean-list
   v    }          # Loop `y` over each of them:
     Rè           #  Take the string "R ", and index the current boolean (0 or 1) in it
    J              #  Join it together with the string of the previous iteration
    …εÿ}           #  Surround it with "ε" and "}"
          RXè     # Index variable `X` also in "R "
              J    # Join it together with the rest
.V                 # Execute string as 05AB1E code

例如:如果布尔输入列表为[1,0,1,1],它将创建以下字符串:

εεεR}R} }R

这将:

  εR}         # Reverse the items in the most inner (4th level) lists
 ε   R}       # Reverse the most inner (3rd level) lists themselves
ε       }     # Do nothing with the inner (2nd level) lists 
         R    # Reverse the entire outer (1st level) list

1
很好的答案,但是...嗯...这11个BYTER可以工作吗?
Xcoder先生,18年

@ Mr.Xcoder谢谢!这确实容易得多。通过追加每个字节,而不是先添加然后反转,可以再打1个字节。
凯文·克鲁伊森

@ Mr.Xcoder顺便说一句,为什么'x*工作重复xn次量,而无需使用sWAP,但它不工作'€*..编辑:只有在传统的,但..
凯文Cruijssen

旧版本有很多错误,可能是由于即使使用char字面量仍被解析为运算符的事实?不敢诚实。在新版本中,*行为方式仍然不同。
Xcoder先生18年

3

JavaScript(Node.js),60字节

一种不同的(递归)方法。还没有击败Arnauld的答案...

将输入作为 array, boolean list

f=(a,r)=>r>[]?(r[0]?a.reverse():a).map(c=>f(c,r.slice(1))):a

f=(a,r)=>r>[]?(r[0]?a.reverse():a).map(c=>f(c,r.slice(1))):a

console.log(f([[[[3,1,4,1],[5,9,2,6]],[[5,3,5,8],[9,7,9,3]]],[[[2,3,8,4],[6,2,6,4]],[[3,3,8,3],[2,7,9,5]]]],[true,false,true,true]))


3

Pyth,15个字节

.v+jk.n*\_*L\ME

在这里尝试!

烦人的是,处理空尺寸列表的情况不小于2个字节...我宁愿ss代替jk.nbut:| 假设要转换的列表可以使用本地Pyth语法作为字符串给出。我已经编写了一个Pyth语法转换器,以简化测试。在不幸的情况下,OP选择不允许这样做,一个17字节的将“修复”它:

.v+jk.n*\_*L\ME\E

3

贾普特15) 14字节

Arnauld解决方案中获得一些启发

将指示作为1s和0s 的布尔数组的第一个输入。

Ê?Vn@ÎãßUÅX:V

试试吧


说明

                   :Implicit input of boolean array U=indications and multi-dimensional integer array V
Ê                  :Get the length of U
 ?                 :If truthy (i.e., >0)
  Vn               :  Sort V
    @ÎÃ            :   Function that gets the first element of U; 0 will leave the array untouched, 1 will reverse it.
       £           :  Map each X
        ß          :  Run the programme again with the following inputs
         UÅ        :   U with the first element removed
           X       :   X will serve as the new value of V
            :      :Else
             V     :  Just return V

3

清除122112字节

import StdEnv
class$r::[Bool]->r->r
instance$r where$_=id
instance$[r]| $r where$[a:y]=if(a)reverse id o map($y)

在线尝试!

使用Clean的golfier类型系统的Damien Haskell答案版本。确实显示了两种语言之间的广泛相似性。

解释:

import StdEnv                 // import basic stuff
class $ r :: [Bool] -> r -> r // $ takes a boolean list and returns a function on r to r
instance $ r                  // instance on all types, taken when no more specific instances exist
    where $ _ = id            // return the identity function for all arguments
instance $ [r] | $ r          // instance for lists of a type which has an instance itself
    where $ [a: y]
        = if(a) reverse id    // reverse if the head of the argument is true
            o map ($ y)       // composed with the map function acting on $ applied to the tail


1

(未经测试,但我认为是正确的。编译器的asm输出看起来像我期望的那样。如果/当我有时间编写编写用于创建和打印此数据结构的测试工具时,它将更新。)

GNU C ++(便携式)148字节

#include<algorithm>
#include<cstdint>
struct m{intptr_t d,l,a[];void R(int*r){if(*r)std::reverse(a,a+l);for(int i=0;d&&i<l;((m*)a[i++])->R(r+1));}};

GNU C ++(int =指针并脱离非无效函数UB)120字节

#include<algorithm>
struct m{int d,l,a[],R(int*r){if(*r)std::reverse(a,a+l);for(int i=0;d&&i<l;((m*)a[i++])->R(r+1));}};

这是深度计数器,长度,{整数或指针}的数组的结构。在此非二叉树(depth==0)的最底层,intptr_t是整数数组。在更高级别,它struct m*存储在中intptr_t。遍历需要强制转换。

R()逆转功能是一个成员函数,因为节省了声明一个精氨酸,以及节省了大量的p->语法来引用结构成员与所述隐式this指针。

唯一的GNU扩展是C99灵活数组成员,用于创建可变大小的struct,C ++将其作为GNU扩展来支持。我本可以用一个*a指向单独分配的数组成员,而这是普通的ISO C ++。(这实际上将节省一个字节,而无需任何其他更改)。我将其编写为asm版本的模型/参考实现。


具有的较短版本int也声明R()为返回int而不是void。这两点黑客无关。这只是“至少在一种实现上有效”的版本。

int只要您使用gcc7或更早版本进行编译,或者禁用优化功能,它就可以在32位目标(可以容纳一个指针)上正常工作。(gcc8 -O3假设执行不能到达非void函数的底部,因为那将是UB。)x86 gcc -m32 -O3应该可以在gcc7 正常工作,就像在Godbolt上,我同时包含了两个版本(在不同的命名空间中)和非成员函数的版本。

不打高尔夫球

函数arg int r[]是由0 /非零整数组成的数组,这些整数指示是否应从最外层开始交换给定深度。

#include<algorithm>  // for std::reverse
#include<cstdint>    // for intptr_t.  GNU C defines __intptr_t, so we could use that...

struct m{
    __intptr_t d,l,a[];    // depth = 0 means values, >0 means pointers.
    // l = length
    //__intptr_t a[];  // flexible array member: array contiguous with the struct

    void R(int r[]) {
        if(*r)
            std::reverse(a, a+l);   // *r && std::reverse() doesn't work because it returns void.

        if(d) // recurse if this isn't the bottom depth
            for(int i=0 ; i<l ; i++)  // tree traversal
                ((m*)a[i])->R(r+1);   // with the rest of the depth list
    }

}; // struct m

递归时,我们通过了r+1,因此检查当前深度始终为*r

较早的版本未r更改并通过r[d]。使用灵活的数组成员,我需要存储某种最后一级的指示器,因为a[]它不是指针,它是没有间接指向的真实数组。但是对于intptr_t *a成员来说,我不能只是nullptr为了叶子而已,因为我希望它成为价值。

在遍历树之前或之后反转当前级别都没有关系。在期间我没有尝试做过。

我不能肯定std::reverse是值得的字节数与手动循环,尤其是如果我能在工作,呼吁R()各指针恰好一次的地方,内循环。但是只有d!=0


哇,令人印象深刻。
亚当

@Adám:谢谢,它在我写完之后自然而然地打了下来。我很好奇我可以在x86机器代码中做什么:P
Peter Cordes

1

Mathematica,7个字节

Reverse

功能。给它一个嵌套列表作为第一个参数,将基于1的级别/维度列表作为第二个参数反转。在线尝试!

最后,Mathematica具有内置功能的另一个挑战!


层反转?可能是TIO链接?
亚当

@Adám也就是说,要反转的尺寸列表,在Mathematica中通常称为级别
LegionMammal978'9
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.