Chỉ số của một mảng nhiều chiều


28

Các ngôn ngữ cấp thấp hơn, chẳng hạn như C và C ++ thực sự không có khái niệm về mảng đa chiều. (Khác với vectơ và mảng động) Khi bạn tạo một mảng nhiều chiều với

int foo[5][10];

Đây thực sự chỉ là cú pháp đường . Những gì C thực sự làm là tạo ra một mảng liền kề gồm 5 phần tử 10 * . Điều này

foo[4][2]

cũng là cú pháp đường. Điều này thực sự đề cập đến các yếu tố tại

4 * 10 + 2

hoặc, phần tử thứ 42. Nói chung, chỉ số của phần tử [a][b]trong mảng foo[x][y]là tại

a * y + b

Khái niệm tương tự áp dụng cho mảng 3d. Nếu chúng ta có foo[x][y][z]và chúng ta truy cập phần tử, [a][b][c]chúng ta thực sự đang truy cập phần tử:

a * y * z + b * z + c

Khái niệm này áp dụng cho mảng n chiều. Nếu chúng ta có một mảng có kích thước D1, D2, D3 ... Dnvà chúng ta truy cập phần tử S1, S2, S3 ... Snthì công thức là

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

Các thách thức

Bạn phải viết một chương trình hoặc hàm tính toán chỉ số của một mảng nhiều chiều theo công thức trên. Đầu vào sẽ là hai mảng. Mảng đầu tiên là kích thước và mảng thứ hai là các chỉ số. Độ dài của hai mảng này sẽ luôn bằng nhau và ít nhất là 1.

Bạn có thể giả định một cách an toàn rằng mọi số trong mảng sẽ là một số nguyên không âm. Bạn cũng có thể giả định rằng bạn sẽ không nhận được một 0mảng kích thước, mặc dù 0 thể nằm trong các chỉ số. Bạn cũng có thể cho rằng các chỉ số sẽ không lớn hơn kích thước.

Kiểm tra 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
Vậy đây là lập chỉ mục dựa trên 0, đúng không? Chúng ta có thể sử dụng lập chỉ mục dựa trên 1 nếu điều đó tự nhiên hơn cho ngôn ngữ chúng ta lựa chọn không?
Alex A.

@AlexA. Vâng, đó là chấp nhận được.
DJMcMayhem

11
Trên thực tế, những gì C 'thực sự làm' là tạo ra một mảng liền kề gồm năm yếu tố loại int[10].


1
@Hurkyl Có, nhưng tất cả các số nguyên trong mảng đó vẫn tiếp tục. Nó chỉ là ngữ nghĩa.
DJMcMayhem

Câu trả lời:


60

APL, 1 byte

Kiểm tra nó trên TryAPL .


21
Vâng, đó là nó. Chúng ta có một người chiến thắng. Mọi người khác có thể về nhà bây giờ.
DJMcMayhem

3
Tại sao ... tại sao điều này hoạt động? o_O
Alex A.

10
@AlexA. Lập chỉ mục một mảng nhiều chiều về cơ bản là chuyển đổi cơ sở hỗn hợp.
Dennis

21
Ôi, nhìn kìa, một lỗ hổng trong khi chơi golf!
Vụ kiện của Quỹ Monica

8
Hầu hết thời gian tôi đến đây cho vui. Rồi có những lúc tôi vô tình nhận được những hiểu biết sâu sắc
slebetman


11

JavaScript (ES6), 34 byte

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

Chắc chắn reducephải tốt hơn map.


7

Python, 43 byte

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

Kiểm tra nó trên Ideone .


15
Dennis không chỉ mạnh mẽ đánh bại tất cả chúng ta, mà anh ấy còn làm điều đó trong mọi. Độc thân. ngôn ngữ.
DJMcMayhem

7

Thạch , 7 6 byte

Ṇ;żḅ@/

Hãy thử trực tuyến! hoặc xác minh tất cả các trường hợp thử nghiệm .

Làm thế nào nó hoạt động

Ṇ;żḅ@/  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 byte

PiPZ}N$X]

Điều này sử dụng lập chỉ mục dựa trên 1 (hiện được cho phép bởi thử thách), đây là lựa chọn tự nhiên trong MATL.

Để so sánh với các trường hợp thử nghiệm trong thử thách, hãy thêm 1vào từng mục trong vectơ chỉ mục đầu vào và trừ đi 1đầu ra.

Hãy thử trực tuyến!

Giải trình

Mã này dựa trên X]hàm dựng sẵn , chuyển đổi các chỉ số đa chiều thành một chỉ số tuyến tính duy nhất (như hàm Matlab hoặc 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 byte

4L)1hPYpP*s

Điều này sử dụng lập chỉ mục dựa trên 0, như trong thử thách ban đầu.

Hãy thử trực tuyến!

Giải trình

Mã rõ ràng thực hiện các phép nhân và bổ sung cần thiết.

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 byte

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

Có lẽ tôi sẽ bị đá bởi những người chơi golf trăn tốt hơn ngoài kia.


4

Con trăn 3.5, 69

lambda d,i:sum(eval("*".join(map(str,[z,*d])))for z in i if d.pop(0))

Kiểm tra tại đây


Câu trả lời tốt đẹp! Tốt hơn nhiều so với của tôi.
DJMcMayhem

@DrGreenEggsand HamDJ Tôi đã đánh cắp phương pháp eval từ giải pháp của bạn :)
Alexander Nigl

4

Haskell, 34 byte

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

Ví dụ sử dụng: [10,10,4,62,7] # [1,2,3,4,5]-> 22167.

Làm thế nào nó hoạt động:

      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 byte

Một macro nhanh chóng:

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

Sử dụng như:

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

Đây có thể là một chút lạm dụng của các quy tắc. Tạo một mảng với kích thước đã cho, hơn là kiểm tra để xem các chỉ mục đã cho bù cho con trỏ bao xa. Đầu ra cho STDOUT.

Cảm giác này thật bẩn thỉu ... Nhưng tôi chỉ thích thực tế rằng điều này là hợp lệ.


3

Toán học, 27 byte

#~FromDigits~MixedRadix@#2&

Hàm không tên được lấy danh sách các chỉ mục làm đối số đầu tiên và danh sách thứ nguyên thứ hai. Dựa trên quan sát tương tự như câu trả lời APL của Dennis rằng tính toán chỉ số thực sự chỉ là một chuyển đổi cơ sở hỗn hợp.


3

Octave, 58 54 byte

Cảm ơn @AlexA. cho đề xuất của mình, đã loại bỏ 4 byte

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

Đầu vào và đầu ra là 1 dựa trên. Để so sánh với các trường hợp kiểm tra, thêm 1ot mỗi mục trong đầu vào và trừ 1khỏi đầu ra.

Đây là một chức năng ẩn danh. Để gọi nó, gán nó cho một biến.

Hãy thử nó ở đây .

Giải trình

Này hoạt động bằng cách thực sự xây dựng các mảng đa chiều ( reshape(...)), đầy giá trị 1, 2... theo thứ tự tuyến tính ( 1:prod(d)), và sau đó lập chỉ mục với chỉ số đa chiều để có được giá trị corrresponding.

Việc lập chỉ mục được thực hiện bằng cách chuyển đổi chỉ mục đa chiều đầu ivào thành một mảng ô ( num2cell(...)) và sau đó thành danh sách được phân tách bằng dấu phẩy ( {:}).

Hai flipthao tác là cần thiết để điều chỉnh thứ tự các kích thước từ C đến Octave.


Tại sao định hình lại có một cặp dấu ngoặc đơn thứ hai không phải là cú pháp?
Abr001am

@ Agawa001 Bạn có nghĩa là một cặp thứ hai sau reshape ? Đó không phải là cú pháp trong Matlab, nhưng được chấp nhận trong Octave. Nó hoạt động như một chỉ mục
Luis Mendo

oh Octave !! điều đó phải tốt hơn và thuận tiện hơn matlab, tha, ks cho sự giác ngộ.
Abr001am

@ Agawa001 Nó cũng có thể dẫn đến một số nhầm lẫn , mặc dù
Luis Mendo

Một mẹo cho các hàm ẩn danh trong mã ví dụ: Tôi sử dụng @(...) ...trong dòng đầu tiên của mã của mình, tiếp theo là f = ans;trong dòng thứ hai. Điều này làm cho độ dài của dòng đầu tiên bằng với số byte cần báo cáo.
bers

3

CJam, 7 byte

0q~z+:b

Hãy thử trực tuyến!

Làm thế nào nó hoạt động

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.

Hãy cho chúng tôi một cơ hội, Dennis! : D
HyperNeutrino

2

Haskell, 47 byte

Hai giải pháp chiều dài bằng nhau:

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

Được gọi như : ((sum.).s)[4,2][5,10].

Đây là một phiên bản infix:

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

2

Octave, 47 / 43 /31 byte

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

Kiểm tra nó ở đây .

Có nói rằng, như đã được hỏi trong một bình luận , lập chỉ mục dựa trên 1 được cho là ổn khi điều này là tự nhiên đối với ngôn ngữ được sử dụng. Trong trường hợp này, chúng ta có thể lưu 4 byte:

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

Tương tự, tôi lập luận rằng nếu mục tiêu của mã là lập chỉ mục tuyến tính một mảng trong ngôn ngữ đó , thì toàn bộ việc lật và tính toán cho thứ tự chính của cột MATLAB / Octave cũng không cần thiết. Trong trường hợp đó, giải pháp của tôi trở thành

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

Kiểm tra cái đó ở đây .


Xin chào, và chào mừng đến với PPCG! Câu trả lời chính xác!
NoOneIsHãy là

1

Toán học, 47 byte

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

(Unicode là U + F3C7 hoặc \[Transpose].) Đối với điều này, tôi viết lại biểu thức là D n ( D n -1 (⋯ ( D 3 ( D 2 S 1 + S 2 ) + S 3 ) ⋯) + S n -1 ) + S n . Chỉ cần Folds chức năng trên cả hai danh sách.


1

Trên thực tế, 13 byte

;pX╗lr`╜tπ`M*

Hãy thử trực tuyến!

Chương trình này lấy danh sách các chỉ số làm đầu vào đầu tiên và danh sách các kích thước làm đầu vào thứ hai.

Giải trình:

;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

Vợt 76 byte

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

Ung dung:

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

Kiểm tra:

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

Đầu ra:

42
22167
37

0

C #, 73 byte

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

Chương trình đầy đủ với các trường hợp thử nghiệm:

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 byte

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

Một sân golf khá ngây thơ ở đây, chỉ cần một tiểu thư vô danh.

Perl 6 có một biến trạng thái ẩn danh $rất hữu ích để tạo bộ đếm trong một vòng lặp (ví dụ: sử dụng tăng sau $++hoặc tăng trước ++$). Tôi tăng trước biến trạng thái này để tăng chỉ số bắt đầu của lát mảng thứ nguyên bên trong bản đồ.

Đây là một hàm không được tạo ra các danh sách phụ

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))

Sau đó, đó chỉ là vấn đề giảm danh sách phụ với toán tử nhân ( ×) và sumlấy kết quả.

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 byte

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

Ung dung:

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 byte

-18 byte để sử dụng 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...);}};

Ung dung:

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
 }
};

Sử dụng:

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

Các chức năng thay thế, chỉ có 116 byte

#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...);};}

Ung dung:

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...);
  };
}

Sử dụng:

f(5,10)(4,2)
f(10,10,10)(4,3,2)
f(10,10,4,62,7)(1,2,3,4,5)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.