Indeks array multidimensi

28

Bahasa tingkat rendah, seperti C dan C ++ sebenarnya tidak memiliki konsep array multidimensi. (Selain vektor dan array dinamis) Saat Anda membuat array multidimensi dengan

int foo[5][10];

Ini sebenarnya hanya gula sintaksis . Apa yang sebenarnya dilakukan C adalah membuat sebuah array bersebelahan yang terdiri dari 5 * 10 elemen. Ini

foo[4][2]

juga merupakan gula sintaksis. Ini benar-benar merujuk pada elemen di

4 * 10 + 2

atau, elemen ke-42. Secara umum, indeks elemen [a][b]dalam array foo[x][y]berada di

a * y + b

Konsep yang sama berlaku untuk array 3d. Jika kita memiliki foo[x][y][z]dan mengakses elemen, [a][b][c]kita benar-benar mengakses elemen:

a * y * z + b * z + c

Konsep ini berlaku untuk n- dimensi array. Jika kita memiliki array dengan dimensi D1, D2, D3 ... Dndan kita mengakses elemen S1, S2, S3 ... Snrumusnya

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

Tantangan

Anda harus menulis program atau fungsi yang menghitung indeks array multidimensi sesuai dengan rumus di atas. Input akan menjadi dua array. Array pertama adalah dimensi, dan array kedua adalah indeks. Panjang kedua array ini akan selalu sama dan setidaknya 1.

Anda dapat dengan aman mengasumsikan bahwa setiap angka dalam array akan menjadi bilangan bulat non-negatif. Anda juga dapat mengasumsikan bahwa Anda tidak akan mendapatkan 0dalam array dimensi, meskipun a 0 mungkin ada dalam indeks. Anda juga dapat mengasumsikan bahwa indeks tidak akan lebih besar dari dimensi.

Tes 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
DJMcMayhem
sumber
4
Jadi ini pengindeksan berbasis 0, benar? Bisakah kita menggunakan pengindeksan berbasis 1 jika itu lebih alami untuk bahasa pilihan kita?
Alex A.
@AlexA. Ya itu bisa diterima.
DJMcMayhem
11
Sebenarnya, apa yang C benar-benar lakukan adalah membuat sebuah array bersebelahan dari lima elemen tipe int[10].
Terkait
Martin Ender
1
@Hurkyl Ya, tetapi semua bilangan bulat di array itu masih bersebelahan. Itu hanya semantik.
DJMcMayhem

Jawaban:

60

APL, 1 byte

Uji di TryAPL .

Dennis
sumber
21
Baiklah, itu saja. Kami punya pemenang. Semua orang bisa pulang sekarang.
DJMcMayhem
3
Kenapa ... mengapa ini bekerja? o_O
Alex A.
10
@AlexA. Pengindeksan array multidimensi pada dasarnya adalah konversi basis campuran.
Dennis
21
Oh, lihat, lubang dalam satu saat bermain golf!
Dana Gugatan Monica
8
Sebagian besar waktu saya datang ke sini untuk bersenang-senang. Kemudian ada saat-saat ketika saya secara tidak sengaja menerima wawasan mendalam
slebetman
11

JavaScript (ES6), 34 byte

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

Tentunya reduceharus lebih baik daripada map.

Neil
sumber
7

Python, 43 byte

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

Uji di Ideone .

Dennis
sumber
15
Tidak hanya Dennis dengan tegas memukul kita semua, tetapi dia melakukannya di setiap. tunggal. bahasa.
DJMcMayhem
7

Jelly , 7 6 byte

Ṇ;żḅ@/

Cobalah online! atau verifikasi semua kasus uji .

Bagaimana itu bekerja

Ṇ;żḅ@/  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.
Dennis
sumber
6

Pyth, 10 byte

e.b=+*ZNYC

Cobalah online: Demonstrasi atau Test Suite

Menggunakan metode Horner untuk menghitung indeks.

Jakube
sumber
5

MATL , 9 byte

PiPZ}N$X]

Ini menggunakan pengindeksan berbasis 1 (sekarang diizinkan oleh tantangan), yang merupakan pilihan alami di MATL.

Untuk membandingkan dengan kasus uji dalam tantangan, tambahkan 1ke setiap entri dalam vektor indeks input, dan kurangi 1dari output.

Cobalah online!

Penjelasan

Kode ini didasarkan pada X]fungsi bawaan , yang mengubah indeks multidimensi menjadi indeks linier tunggal (seperti sub2indfungsi Matlab atau Oktaf ).

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
Luis Mendo
sumber
5

Julia, 29 27 byte

x%y=prod(x)÷cumprod(x)⋅y

Cobalah online!

Dennis
sumber
5

MATL , 11 byte

4L)1hPYpP*s

Ini menggunakan pengindeksan berbasis 0, seperti pada tantangan aslinya.

Cobalah online!

Penjelasan

Kode secara eksplisit melakukan penggandaan dan penambahan yang dibutuhkan.

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
Luis Mendo
sumber
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)))

Saya mungkin akan mendapatkan pantat saya ditendang oleh pegolf python yang lebih baik di luar sana.

DJMcMayhem
sumber
4

Python 3.5, 69

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

Tes di sini

Alexander Nigl
sumber
Jawaban bagus! Jauh lebih baik dari milikku.
DJMcMayhem
@DrGreenEggsandHamDJ Saya mencuri metode eval dari solusi Anda :)
Alexander Nigl
4

Haskell, 34 byte

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

Contoh penggunaan: [10,10,4,62,7] # [1,2,3,4,5]-> 22167.

Bagaimana itu bekerja:

      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
nimi
sumber
4

C ++, 66 byte

Makro cepat:

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

Gunakan seperti:

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

Ini mungkin sedikit penyalahgunaan aturan. Membuat array dengan ukuran yang diberikan, daripada memeriksa untuk melihat seberapa jauh indeks yang diberikan mengimbangi pointer. Output ke STDOUT.

Ini terasa sangat kotor ... Tapi saya suka fakta ini valid.

MegaTom
sumber
3

Mathematica, 27 byte

#~FromDigits~MixedRadix@#2&

Fungsi tanpa nama yang mengambil daftar indeks sebagai argumen pertama dan daftar dimensi kedua. Berdasarkan pengamatan yang sama dengan jawaban APL Dennis yang menghitung indeks benar-benar hanya konversi campuran-basis.

Martin Ender
sumber
3

Oktaf, 58 54 byte

Terima kasih kepada @AlexA. untuk sarannya, yang menghapus 4 byte

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

Input dan output berbasis 1. Untuk membandingkan dengan kasus uji, tambahkan 1setiap entri dalam input dan kurangi 1dari output.

Ini adalah fungsi anonim. Untuk menyebutnya, tetapkan ke variabel.

Coba di sini .

Penjelasan

Ini bekerja dengan benar-benar membangun array multidimensi ( reshape(...)), diisi dengan nilai-nilai 1, 2... dalam rangka linear ( 1:prod(d)), dan kemudian mengindeks dengan indeks multidimensi untuk mendapatkan nilai corrresponding.

Pengindeksan dilakukan dengan mengubah input indeks multidimensi imenjadi array sel ( num2cell(...)) dan kemudian ke daftar yang dipisahkan koma ( {:}).

Dua flipoperasi diperlukan untuk mengadaptasi urutan dimensi dari C ke Oktaf.

Luis Mendo
sumber
mengapa membentuk ulang memiliki pasangan kedua kurung bukankah itu sintaksis?
Abr001am
@ Agawa001 Apakah maksud Anda pasangan kedua setelah reshape ? Itu bukan sintaksis dalam Matlab, tetapi diterima dalam Oktaf. Ini berfungsi sebagai indeks
Luis Mendo
oh oktaf !! yang harus lebih baik dan lebih ergonomis daripada matlab, tha, ks untuk pencerahan.
Abr001am
@ Agawa001 Ini juga dapat menyebabkan beberapa kebingungan ,
Luis Mendo
Kiat untuk fungsi anonim dalam kode contoh: Saya gunakan @(...) ...di baris pertama kode saya, diikuti oleh f = ans;yang kedua. Ini membuat panjang baris pertama sama dengan jumlah byte yang dilaporkan.
bers
3

CJam, 7 byte

0q~z+:b

Cobalah online!

Bagaimana itu bekerja

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.
Dennis
sumber
Beri kami kesempatan, Dennis! : D
HyperNeutrino
2

Haskell, 47 byte

Dua solusi panjang yang sama:

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

Disebut seperti: ((sum.).s)[4,2][5,10].

Ini versi infiks:

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

Oktaf, 47 / 43 /31 bytes

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

Uji di sini .

Karena itu, seperti yang diminta dalam komentar , pengindeksan berbasis 1 dikatakan OK ketika ini alami untuk bahasa yang digunakan. Dalam hal ini, kita dapat menyimpan 4 byte:

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

Dalam analogi, saya berpendapat bahwa jika tujuan dari kode ini adalah untuk mengindeks secara linear sebuah array dalam bahasa itu , keseluruhan membalik dan menghitung untuk MATLAB / Octave, urutan utama kolom juga tidak perlu. Dalam hal ini, solusi saya menjadi

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

Uji yang itu di sini .

bers
sumber
Halo, dan selamat datang di PPCG! Jawaban bagus!
NoOneIsHere
1

Mathematica, 47 byte

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

(Unicode adalah U + F3C7, atau \[Transpose].) Untuk ini, saya menulis ulang ekspresi sebagai D n ( D n -1 (⋯ ( D 3 ( D 2 S 1 + S 2 ) + S 3 ) ⋯) + S n -1 ) + S n . Hanya Foldfungsi dari kedua daftar.

LegionMammal978
sumber
1

Sebenarnya, 13 byte

;pX╗lr`╜tπ`M*

Cobalah online!

Program ini mengambil daftar indeks sebagai input pertama dan daftar dimensi sebagai input kedua.

Penjelasan:

;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
Mego
sumber
1

Racket 76 byte

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

Tidak Terkumpul:

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

Pengujian:

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

Keluaran:

42
22167
37
juga
sumber
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;};

Program lengkap dengan uji kasus:

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
        }
    }
}
adrianmp
sumber
0

Perl 6, 39 byte

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

Golf yang agak naif di sini, hanya memeras sub anonim.

Perl 6 memiliki variabel status anonim $yang berguna untuk membuat penghitung dalam satu lingkaran (misalnya, menggunakan penambahan $++atau pra-kenaikan ++$). Saya melakukan pra-kenaikan variabel status ini untuk menambah indeks awal dari irisan larik dimensi di dalam peta.

Berikut adalah fungsi yang tidak dikenali yang membuat sub-daftar

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

Maka tinggal mengurangi sub-daftar dengan ×operator multiplikasi ( ), dan sumhasilnya.

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
Joshua
sumber
0

Perl, 71 byte

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

Tidak Terkumpul:

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

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

    return $s;
}
Denis Ibaev
sumber
0

C ++ 17, 133 115 byte

-18 byte untuk digunakan 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...);}};

Tidak Terkumpul:

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

Pemakaian:

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

Alternatif, hanya fungsi, 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...);};}

Tidak Terkumpul:

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

Pemakaian:

f(5,10)(4,2)
f(10,10,10)(4,3,2)
f(10,10,4,62,7)(1,2,3,4,5)
Karl Napf
sumber