Index eines mehrdimensionalen Arrays

28

Untergeordnete Sprachen wie C und C ++ haben eigentlich kein Konzept für mehrdimensionale Arrays. (Andere als Vektoren und dynamische Arrays) Wenn Sie ein mehrdimensionales Array mit erstellen

int foo[5][10];

Dies ist eigentlich nur syntaktischer Zucker . Was C wirklich tut, ist, ein einzelnes zusammenhängendes Array von 5 * 10 Elementen zu erstellen . Dies

foo[4][2]

ist auch syntaktischer Zucker. Das bezieht sich wirklich auf das Element bei

4 * 10 + 2

oder das 42. Element. Im Allgemeinen ist der Index des Elements [a][b]im Array foo[x][y]at

a * y + b

Das gleiche Konzept gilt für 3D-Arrays. Wenn wir haben foo[x][y][z]und auf element [a][b][c]zugreifen, greifen wir wirklich auf element zu:

a * y * z + b * z + c

Dieses Konzept gilt für n- dimensionale Arrays. Wenn wir ein Array mit Dimensionen haben D1, D2, D3 ... Dnund auf das Element zugreifen, S1, S2, S3 ... Snlautet die Formel

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

Die Herausforderung

Sie müssen ein Programm oder eine Funktion schreiben, die den Index eines mehrdimensionalen Arrays gemäß der obigen Formel berechnet. Die Eingabe erfolgt über zwei Arrays. Das erste Array sind die Dimensionen und das zweite Array sind die Indizes. Die Länge dieser beiden Arrays ist immer gleich und mindestens 1.

Sie können davon ausgehen, dass jede Zahl in den Arrays eine nicht negative Ganzzahl ist. Sie können auch davon ausgehen, dass Sie kein a 0im Dimensionsarray erhalten, obwohl a 0 möglicherweise in den Indizes enthalten ist. Sie können auch davon ausgehen, dass die Indizes nicht größer als die Dimensionen sind.

Testen Sie 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
quelle
4
Das ist also eine 0-basierte Indizierung, richtig? Können wir eine 1-basierte Indizierung verwenden, wenn dies für die Sprache unserer Wahl natürlicher ist?
Alex A.
@AlexA. Ja, das ist akzeptabel.
DJMcMayhem
11
Tatsächlich erzeugt C 'wirklich' ein einzelnes zusammenhängendes Array von fünf Elementen des Typs int[10].
Verbunden.
Martin Ender
1
@Hurkyl Ja, aber alle Ganzzahlen in diesem Array sind immer noch zusammenhängend. Es ist nur Semantik.
DJMcMayhem

Antworten:

60

APL, 1 Byte

Testen Sie es auf TryAPL .

Dennis
quelle
21
Das war's. Wir haben einen Sieger. Alle anderen können jetzt nach Hause gehen.
DJMcMayhem
3
Warum ... warum funktioniert das? o_O
Alex A.
10
@AlexA. Das Indizieren eines mehrdimensionalen Arrays ist im Wesentlichen eine gemischte Basiskonvertierung.
Dennis
21
Oh, schau, ein Loch in einem beim Golfen!
Fund Monicas Klage
8
Die meiste Zeit komme ich zum Spaß hierher. Dann gibt es Zeiten, in denen ich versehentlich tiefgreifende Erkenntnisse
erhalte
11

JavaScript (ES6), 34 Byte

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

Sicherlich reducemuss besser sein als map.

Neil
quelle
7

Python, 43 Bytes

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

Teste es auf Ideone .

Dennis
quelle
15
Dennis verprügelt uns nicht nur fest, sondern er tut es in jedem
DJMcMayhem
7

Gelee , 7 6 Bytes

Ṇ;żḅ@/

Probieren Sie es online! oder überprüfen Sie alle Testfälle .

Wie es funktioniert

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

Pyth, 10 Bytes

e.b=+*ZNYC

Probieren Sie es online aus: Demo oder Test Suite

Verwenden Sie die Horner-Methode, um den Index zu berechnen.

Jakube
quelle
5

MATL , 9 Bytes

PiPZ}N$X]

Dies verwendet eine 1-basierte Indizierung (die jetzt von der Challenge zugelassen wird), was in MATL die natürliche Wahl ist.

Fügen Sie 1zu jedem Eintrag im Eingabeindexvektor einen Wert hinzu und subtrahieren Sie 1den Wert von der Ausgabe, um ihn mit den Testfällen in der Abfrage zu vergleichen .

Probieren Sie es online!

Erläuterung

Der Code basiert auf der eingebauten X]Funktion, die mehrdimensionale Indizes in einen einzelnen linearen Index konvertiert (wie die Matlab- oder Octave- sub2indFunktion).

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
quelle
5

MATL , 11 Bytes

4L)1hPYpP*s

Dies verwendet eine 0-basierte Indizierung, wie bei der ursprünglichen Abfrage.

Probieren Sie es online!

Erläuterung

Der Code führt explizit die erforderlichen Multiplikationen und Additionen durch.

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
quelle
4

Python, 85 Bytes

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

Ich werde wahrscheinlich meinen Hintern von den besseren Python-Golfern da draußen treten lassen.

DJMcMayhem
quelle
4

Python 3.5, 69

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

testen Sie hier

Alexander Nigl
quelle
Gute Antwort! Viel besser als meins.
DJMcMayhem
@ DrGreenEggsandHamDJ Ich habe die Bewertungsmethode aus Ihrer Lösung gestohlen :)
Alexander Nigl
4

Haskell, 34 Bytes

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

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

Wie es funktioniert:

      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
quelle
4

C ++, 66 Bytes

Ein kurzes Makro:

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

Verwenden Sie wie:

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

Dies könnte ein Missbrauch der Regeln sein. Erstellt ein Array mit der angegebenen Größe und überprüft dann, inwieweit die angegebenen Indizes den Zeiger versetzen. Ausgänge zu STDOUT.

Das fühlt sich so dreckig an ... Aber ich liebe die Tatsache, dass dies gültig ist.

MegaTom
quelle
3

Mathematica, 27 Bytes

#~FromDigits~MixedRadix@#2&

Eine unbenannte Funktion, die die Liste der Indizes als erstes Argument und die Liste der Dimensionen als zweites verwendet. Basierend auf derselben Beobachtung wie Dennis 'APL-Antwort, dass die Berechnung des Index nur eine Mixed-Base-Konvertierung ist.

Martin Ender
quelle
3

Oktave, 58 54 Bytes

Vielen Dank an @AlexA. für seinen Vorschlag, der 4 Bytes entfernte

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

Eingang und Ausgang sind 1-basiert. Fügen Sie zum Vergleich mit den Testfällen 1jeden Eintrag in der Eingabe hinzu und subtrahieren Sie ihn 1von der Ausgabe.

Dies ist eine anonyme Funktion. Um es aufzurufen, weisen Sie es einer Variablen zu.

Probieren Sie es hier aus .

Erläuterung

Dies funktioniert , indem tatsächlich den mehrdimensionale Array Aufbau ( reshape(...)), mit Werten gefüllt 1, 2... in linearer Reihenfolge ( 1:prod(d)) und dann die Indizierung mit dem mehrdimensionalen Index den corrresponding Wert zu erhalten.

Die Indizierung erfolgt durch Konvertieren des mehrdimensionalen Eingabeindex iin ein Zellenarray ( num2cell(...)) und anschließend in eine durch Kommas getrennte Liste ( {:}).

Diese beiden flipOperationen sind erforderlich, um die Reihenfolge der Dimensionen von C bis Oktave anzupassen.

Luis Mendo
quelle
Warum hat die Umformung ein zweites Klammerpaar, das nicht syntaktisch ist?
9.
@ Agawa001 Meinst du ein zweites Paar danach reshape ? Das ist in Matlab nicht syntaktisch, wird aber in Octave akzeptiert. Es funktioniert als Index
Luis Mendo
oh oktave !! das muss besser und ergonomischer sein als matlab, tha, ks für erleuchtung.
9.
@ Agawa001 Es kann auch führen einige Verwirrung aber
Luis Mendo
Ein Tipp für anonyme Funktionen im Beispielcode: Ich verwende @(...) ...in der ersten Zeile meines Codes, gefolgt von f = ans;der zweiten. Dadurch entspricht die Länge der ersten Zeile der Anzahl der zu meldenden Bytes.
bers
3

CJam, 7 Bytes

0q~z+:b

Probieren Sie es online!

Wie es funktioniert

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
quelle
Gib uns eine Chance, Dennis! : D
HyperNeutrino
2

Haskell, 47 Bytes

Zwei gleichlange Lösungen:

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

Genannt wie: ((sum.).s)[4,2][5,10].

Hier ist eine Infix-Version:

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

Octave, 47 / 43 /31 Byte

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

Teste es hier .

Allerdings wurde, wie in einem Kommentar gefordert , die 1-basierte Indizierung als OK eingestuft, wenn dies für die verwendete Sprache natürlich ist. In diesem Fall können wir 4 Bytes sparen:

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

In Analogie dazu behaupte ich, dass, wenn das Ziel des Codes darin besteht, ein Array innerhalb dieser Sprache linear zu indizieren , das gesamte Umblättern und Berücksichtigen der Spaltenhauptreihenfolge von MATLAB / Octave ebenfalls nicht erforderlich sein sollte. In diesem Fall wird meine Lösung

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

Testen Sie das hier .

bers
quelle
Hallo und willkommen bei PPCG! Gute Antwort!
NoOneIsHere
1

Mathematica, 47 Bytes

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

(Unicode ist U + F3C7 oder \[Transpose].) Dazu habe ich den Ausdruck umgeschrieben als D n ( D n –1 (⋯ ( D 3 ( D 2 S 1 + S 2 ) + S 3 ) ⋯) + S n –1 ) + S n . Einfach Folds die Funktion über beide Listen.

LegionMammal978
quelle
1

Eigentlich 13 Bytes

;pX╗lr`╜tπ`M*

Probieren Sie es online!

Dieses Programm verwendet die Liste der Indizes als erste Eingabe und die Liste der Dimensionen als zweite Eingabe.

Erläuterung:

;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
quelle
1

Schläger 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))))))))

Testen:

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

Ausgabe:

42
22167
37
rnso
quelle
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;};

Volles Programm mit Testfällen:

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
quelle
0

Perl 6, 39 Bytes

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

Ein eher naiver Golf hier, der gerade ein anonymes U-Boot gequetscht hat.

Perl 6 verfügt über eine anonyme Statusvariable, $die zum Erstellen eines Zählers in einer Schleife nützlich ist (z. B. mithilfe von Post-Inkrement $++oder Pre-Inkrement ++$). Ich inkrementiere diese Statusvariable vorab, um den Startindex des Dimensionsarray-Slice innerhalb einer Karte zu inkrementieren.

Hier ist eine ungolfed Funktion, die die Unterlisten erstellt

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

Dann geht es nur noch darum, die Unterlisten mit dem multiplication ( ×) -Operator zu sumverkleinern und die Ergebnisse zu erhalten.

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
quelle
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;
}
Denis Ibaev
quelle
0

C ++ 17, 133 115 Bytes

-18 Bytes für die Verwendung 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
 }
};

Verwendung:

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

Alternativ nur Funktionen, 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...);
  };
}

Verwendung:

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
quelle