多维数组的索引


28

较低级的语言(例如C和C ++)实际上没有多维数组的概念。(向量和动态数组除外)使用以下方法创建多维数组时

int foo[5][10];

这实际上只是语法糖。C真正要做的是创建一个由5 * 10个元素组成的连续数组。这个

foo[4][2]

也是语法糖。这实际上是指

4 * 10 + 2

或者,第42个元素。一般地,元件的索引[a][b]在阵列foo[x][y]是在

a * y + b

相同的概念适用于3d阵列。如果我们有foo[x][y][z]并且访问元素,那么[a][b][c]我们实际上是在访问元素:

a * y * z + b * z + c

这个概念适用于n维数组。如果我们有一个具有维度的数组D1, D2, D3 ... Dn并且我们访问元素,S1, S2, S3 ... Sn则公式为

(S1 * D2 * D3 ... * Dn) + (S2 * D3 * D4 ... * Dn) + (S3 * D4 ... * Dn) ... + (Sn-1 * Dn) + Sn

挑战

您必须编写一个程序或函数来根据上述公式计算多维数组的索引。输入将是两个数组。第一个数组是维度,第二个数组是索引。这两个数组的长度将始终相等且至少为1。

您可以安全地假定数组中的每个数字都是非负整数。您还可以假设0尽管索引中0 可能包含a,但在维度数组中不会得到a 。您还可以假定索引不会大于维度。

测试IO

Dimensions: [5, 10]
Indices: [4, 2]
Output: 42

Dimensions: [10, 10, 4, 62, 7]
Indices: [1, 2, 3, 4, 5]
Output: 22167

Dimensions: [5, 1, 10]
Indices: [3, 0, 7]
Output: 37

Dimensions: [6, 6, 6, 6, 6, 6, 6, 6, 6, 6]
Indices: [3, 1, 5, 5, 3, 0, 5, 2, 5, 4]
Output: 33570178

4
所以这是基于0的索引,对吗?如果我们选择的语言更自然,我们可以使用基于1的索引吗?
— Alex A.

@AlexA。是的,可以接受。
— DJMcMayhem

11
实际上,C的“真正作用”是创建一个由五个type元素组成的连续数组int[10]。


1
@Hurkyl是的,但是该数组中的所有整数仍然是连续的。这只是语义。
— DJMcMayhem

Answers:


60

APL,1个字节

⊥

在TryAPL上进行测试。


21
好吧,就是这样。我们有一个赢家。现在所有人都可以回家了。
— DJMcMayhem

3
为什么...为什么这样做?o_O
— Alex A.

10
@AlexA。索引多维数组本质上是混合基础转换。
— 丹尼斯

21
哦,看,打高尔夫球时一个洞!
— 基金莫妮卡的诉讼

8
大多数时候我来这里都是为了好玩。然后有时候我会意外地得到深刻的见解
— slebetman's


11

JavaScript(ES6),34个字节

(d,a)=>a.reduce((r,i,j)=>r*d[j]+i)

当然reduce一定比更好map。


7

Python,43个字节

f=lambda x,y:x>[]and y.pop()+x.pop()*f(x,y)

在Ideone上进行测试。


15
丹尼斯不仅坚定地击败了我们所有人,而且他在每一个人
— DJMcMayhem

7

果冻,7 6 字节

Ṇ;żḅ@/

在线尝试!或验证所有测试用例。

怎么运行的

Ṇ;żḅ@/  Main link. Arguments: D (list of dimensions), I (list of indices)

Ṇ       Yield 0, the logical NOT of D.
  ż     Zip D with I.
        If D = [10, 10, 4, 62, 7] and I = [1, 2, 3, 4, 5], this yields
        [[10, 1], [10, 2], [4, 3], [62, 4], [7, 5]].
 ;      Concatenate, yielding [0, [10, 1], [10, 2], [4, 3], [62, 4], [7, 5]].
   ḅ@/  Reduce by swapped base conversion to integer.
        [10, 1] in base    0 is    0 × 10 + 1 = 1.
        [10, 2] in base    1 is    1 × 10 + 2 = 12.
        [ 4, 3] in base   12 is   12 ×  4 + 3 = 51.
        [62, 4] in base   51 is   51 × 62 + 4 = 3166.
        [ 7, 5] in base 3166 is 3166 ×  7 + 5 = 22167.


5

MATL,9个字节

PiPZ}N$X]

它使用基于1的索引(现在挑战允许),这是MATL中的自然选择。

要与挑战中的测试用例进行比较,将其添加1到输入索引向量的每个条目中,然后1从输出中减去。

在线尝试!

说明

该代码基于内置X]函数,该函数将多维索引转换为单个线性索引(例如Matlab或Octave sub2ind函数)。

P      % Take dimension vector implicitly. Reverse
iP     % Take vector of indices. Reverse
Z}     % Split vector into its elements
N$X]   % Convert indices to linear index (`sub2ind` function). Implicitly display


5

MATL,11个字节

4L)1hPYpP*s

与原始挑战一样,它使用基于0的索引。

在线尝试!

说明

该代码明确执行所需的乘法和加法。

4L)    % Take first input array implicitly. Remove its first entry
1h     % Append a 1
PYpP   % Cumulative product from right to left
*      % Take second input array implicitly. Multiply the two arrays element-wise
s      % Sum of resulting array. Implicitly display

4

Python,85个字节

lambda a,b:sum(b[i]*eval('*'.join(str(n)for n in a[i+1:])or'1')for i in range(len(a)))

我可能会被更好的蟒蛇高尔夫球手踢屁股。



4

Haskell,34个字节

a#b=sum$zipWith(*)(0:b)$scanr(*)1a

用法示例:[10,10,4,62,7] # [1,2,3,4,5]->22167。

怎么运行的:

      scanr(*)1a  -- build partial products of the first parameter from the right,
                  -- starting with 1, e.g. [173600,17360,1736,434,7,1]
    (0:b)         -- prepend 0 to second parameter, e.g. [0,1,2,3,4,5]
  zipWith(*)      -- multiply both lists elementwise, e.g. [0,17360,3472,1302,28,5]
sum               -- calculate sum

4

C ++,66个字节

快速宏:

#include<stdio.h>
#define F(d,i) int x d;printf("%d",&x i-(int*)x)

使用方式如下:

int main(){
    F([5][1][10], [3][0][7]);
}

这可能是对规则的滥用。创建一个具有给定大小的数组,然后检查给定索引将指针偏移多远。输出到STDOUT。

感觉很脏...但是我只是喜欢这样的事实。


3

Mathematica,27个字节

#~FromDigits~MixedRadix@#2&

一个未命名的函数,它将索引列表作为第一个参数,将维度列表作为第二个参数。基于与Dennis的APL回答相同的观察结果,计算索引实际上只是一个混合基准转换。


3

Octave, 58 54 bytes

Thanks to @AlexA. for his suggestion, which removed 4 bytes

@(d,i)reshape(1:prod(d),flip(d))(num2cell(flip(i)){:})

Input and output are 1-based. To compare with the test cases, add 1 ot each entry in the input and subtract 1 from the output.

This is an anonymous function. To call it, assign it to a variable.

Try it here.

Explanation

This works by actually building the multidimensional array (reshape(...)), filled with values 1, 2, ... in linear order (1:prod(d)), and then indexing with the multidimensional index to get the corrresponding value.

The indexing is done by converting the input multidimensional index i into a cell array (num2cell(...)) and then to a comma-separated list ({:}).

The two flip operations are needed to adapt the order of dimensions from C to Octave.


why does reshape have a second pair of parenthesis isnt that non syntactic?
— Abr001am

@Agawa001 Do you mean a second pair after reshape? That's non syntactic in Matlab, but accepted in Octave. It works as an index
— Luis Mendo

oh Octave!! that must be better and more ergonomic than matlab , tha,ks for enlightenment.
— Abr001am

@Agawa001 It can also lead to some confusion, though
— Luis Mendo

A tip for anonymous functions in example code: I use @(...) ... in the first line of my code, followed by f = ans; in the second. This makes the length of the first line equal to the number of bytes to report.
— bers

3

CJam, 7 bytes

0q~z+:b

Try it online!

How it works

0        e# Push 0 on the stack.
 q       e# Read and push all input, e.g., "[[10 10 4 62 7] [1 2 3 4 5]]".
  ~      e# Eval, pushing [[10 10 4 62 7] [1 2 3 4 5]].
   z     e# Zip, pushing [[10 1] [10 2] [4 3] [62 4] [7 5]].
    +    e# Concatenate, pushing [0 [10 1] [10 2] [4 3] [62 4] [7 5]]
     :b  e# Reduce by base conversion.
         e# [10 1] in base    0 is    0 * 10 + 1 = 1.
         e# [10 2] in base    1 is    1 * 10 + 2 = 12.
         e# [ 4 3] in base   12 is   12 *  4 + 3 = 51.
         e# [62 4] in base   51 is   51 * 62 + 4 = 3166.
         e# [ 7 5] in base 3166 is 3166 *  7 + 5 = 22167.

Give us a chance, Dennis! :D
— HyperNeutrino

2

Haskell, 47 bytes

Two equal length solutions:

s(a:b)(x:y)=a*product y:s b y
s _ _=[]
(sum.).s

Called like: ((sum.).s)[4,2][5,10].

Here's an infix version:

(a:b)&(x:y)=a*product y:b&y
_ & _=[]
(sum.).(&)

2

Octave, 47/43/31 bytes

@(d,i)sub2ind(flip(d),num2cell(flip(i+1)){:})-1

Test it here.

Having said that, as it was asked in a comment, 1-based indexing was said to be OK when this is natural to the language being used. In this case, we can save 4 bytes:

@(d,i)sub2ind(flip(d),num2cell(flip(i)){:})

In analogy, I argue that if the objective of the code is to linearly index an array within that language, the whole flipping around and accounting for MATLAB/Octave's column major order should not be necessary, either. In that case, my solution becomes

@(d,i)sub2ind(d,num2cell(i){:})

Test that one here.


Hello, and welcome to PPCG! Great answer!
— NoOneIsHere

1

Mathematica, 47 bytes

Fold[Last@#2#+First@#2&,First@#,Rest/@{##}]&

(Unicode is U+F3C7, or \[Transpose].) For this, I rewrote the expression as Dn(Dn-1( ⋯ (D3(D2S1 + S2) + S3) ⋯ ) + Sn-1) + Sn. Just Folds the function over both lists.


1

Actually, 13 bytes

;pX╗lr`╜tπ`M*

Try it online!

This program takes the list of indices as the first input and the list of dimensions as the second input.

Explanation:

;pX╗lr`╜tπ`M*
;pX╗            push dims[1:] to reg0
    lr`   `M    map: for n in range(len(dims)):
       ╜tπ        push product of last n values in reg0
            *   dot product of indices and map result

1

Racket 76 bytes

(λ(l i(s 0))(if(null? i)s(f(cdr l)(cdr i)(+ s(*(car i)(apply *(cdr l)))))))

Ungolfed:

(define f
  (λ (ll il (sum 0))
    (if (null? il)
        sum
        (f (rest ll)
           (rest il)
           (+ sum
              (* (first il)
                 (apply * (rest ll))))))))

Testing:

(f '(5 10) '(4 2))
(f '(10 10 4 62 7) '(1 2 3 4 5))
(f '(5 1 10) '(3 0 7))

Output:

42
22167
37

0

C#, 73 bytes

d=>i=>{int n=d.Length,x=0,y=1;for(;n>0;){x+=y*i[--n];y*=d[n];}return x;};

Full program with test cases:

using System;

namespace IndexOfAMultidimensionalArray
{
    class Program
    {
        static void Main(string[] args)
        {
            Func<int[],Func<int[],int>>f= d=>i=>{int n=d.Length,x=0,y=1;for(;n>0;){x+=y*i[--n];y*=d[n];}return x;};

            int[] dimensions, indices;
            dimensions =new int[]{5, 10};
            indices=new int[]{4,2};
            Console.WriteLine(f(dimensions)(indices));      //42

            dimensions=new int[]{10, 10, 4, 62, 7};
            indices=new int[]{1, 2, 3, 4, 5};
            Console.WriteLine(f(dimensions)(indices));      //22167

            dimensions=new int[]{5, 1, 10};
            indices=new int[]{3, 0, 7};
            Console.WriteLine(f(dimensions)(indices));      //37

            dimensions=new int[]{6, 6, 6, 6, 6, 6, 6, 6, 6, 6};
            indices=new int[]{3, 1, 5, 5, 3, 0, 5, 2, 5, 4};
            Console.WriteLine(f(dimensions)(indices));      //33570178
        }
    }
}

0

Perl 6, 39 bytes

->\d,\i{sum i.map:{[×] $_,|d[++$ ..*]}}

A rather naive golf here, just squished a anonymous sub.

Perl 6 has an anonymous state variable $ which is useful for creating a counter in a loop (eg, using post-increment $++ or pre-increment ++$). I pre-increment this state variable to increment the starting index of the dimension array slice inside a map.

Here's a ungolfed function that creates the sub-lists

sub md-index(@dim, @idx) {
    @idx.map(-> $i { $i, |@dim[++$ .. *] })
}
say md-index([10, 10, 4, 62, 7], [1, 2, 3, 4, 5]);
# OUTPUT: ((1 10 4 62 7) (2 4 62 7) (3 62 7) (4 7) (5))

Then it's just a matter of reducing the sub-lists with the multiplication (×) operator, and suming the results.

sub md-index(@dim, @idx) {
    @idx.map(-> $i { [×] $i, |@dim[++$ .. *] }).sum
}
say md-index([10, 10, 4, 62, 7], [1, 2, 3, 4, 5]);
# OUTPUT: 22167

0

Perl, 71 bytes

sub{$s+=$_[1][-$_]*($p*=$_[0][1-$_])for($p=$_[0][$s=0]=1)..@{$_[0]};$s}

Ungolfed:

sub {
    my $s = 0;
    my $p = 1;

    $_[0]->[0] = 1;
    for (1 .. @{$_[1]}) {
        $p *= $_[0]->[1 - $_];
        $s += $_[1]->[-$_] * $p;
    }

    return $s;
}

0

C++17, 133 115 bytes

-18 bytes for using auto...

template<int d,int ...D>struct M{int f(int s){return s;}int f(int s,auto...S){return(s*...*D)+M<D...>().f(S...);}};

Ungolfed:

template <int d,int ...D> //extract first dimension
struct M{
 int f(int s){return s;} //base case for Sn
 int f(int s, auto... S) { //extract first index 
  return (s*...*D)+M<D...>().f(S...); 
  //S_i * D_(i+1) * D(i+2) * ... + recursive without first dimension and first index
 }
};

Usage:

M<5,10>().f(4,2)
M<10,10,4,62,7>().f(1,2,3,4,5)

Alternative, only functions, 116 bytes

#define R return
#define A auto
A f(A d){R[](A s){R s;};}A f(A d,A...D){R[=](A s,A...S){R(s*...*D)+f(D...)(S...);};}

Ungolfed:

auto f(auto d){
  return [](auto s){
   return s;
  };
}
auto f(auto d, auto...D){
  return [=](auto s, auto...S){
    return (s*...*D)+f(D...)(S...);
  };
}

Usage:

f(5,10)(4,2)
f(10,10,10)(4,3,2)
f(10,10,4,62,7)(1,2,3,4,5)
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.