多维数组的索引


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.