Index d'un tableau multidimensionnel


28

Les langages de niveau inférieur, tels que C et C ++, n'ont en réalité aucun concept de tableaux multidimensionnels. (Autre que les vecteurs et les tableaux dynamiques) Lorsque vous créez un tableau multidimensionnel avec

int foo[5][10];

Ce n'est en fait que du sucre syntaxique . Ce que C fait vraiment, c'est créer un seul tableau contigu de 5 * 10 éléments. Cette

foo[4][2]

est également du sucre syntaxique. Cela fait vraiment référence à l'élément

4 * 10 + 2

ou, le 42e élément. En général, l'indice de l'élément [a][b]dans le tableau foo[x][y]est à

a * y + b

Le même concept s'applique aux tableaux 3D. Si nous avons foo[x][y][z]et nous [a][b][c]accédons à l'élément, nous accédons vraiment à l'élément:

a * y * z + b * z + c

Ce concept s'applique aux tableaux à n dimensions. Si nous avons un tableau avec des dimensions D1, D2, D3 ... Dnet que nous accédons à l'élément, S1, S2, S3 ... Snla formule est

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

Le défi

Vous devez écrire un programme ou une fonction qui calcule l'index d'un tableau multidimensionnel selon la formule ci-dessus. L'entrée sera deux tableaux. Le premier tableau correspond aux dimensions et le second tableau aux indices. La longueur de ces deux tableaux sera toujours égale et d'au moins 1.

Vous pouvez supposer en toute sécurité que chaque nombre dans les tableaux sera un entier non négatif. Vous pouvez également supposer que vous n'obtiendrez pas a 0dans le tableau de dimensions, bien que a 0 puisse être dans les indices. Vous pouvez également supposer que les indices ne seront pas supérieurs aux dimensions.

Test 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
Il s'agit donc d'une indexation basée sur 0, n'est-ce pas? Pouvons-nous utiliser l'indexation basée sur 1 si cela est plus naturel pour notre langue de choix?
Alex A.

@AlexA. Oui, c'est acceptable.
DJMcMayhem

11
En fait, ce que «fait vraiment», c'est créer un seul tableau contigu de cinq éléments de type int[10].


1
@Hurkyl Oui, mais tous les entiers de ce tableau sont toujours contigus. C'est juste de la sémantique.
DJMcMayhem

Réponses:


60

APL, 1 octet

Testez-le sur TryAPL .


21
Eh bien c'est ça. Nous avons un gagnant. Tout le monde peut rentrer chez lui maintenant.
DJMcMayhem

3
Pourquoi ... pourquoi ça marche? o_O
Alex A.

10
@AlexA. L'indexation d'un tableau multidimensionnel est essentiellement une conversion de base mixte.
Dennis

21
Oh, regardez, un trou en un tout en jouant au golf!
Fund Monica's Lawsuit

8
La plupart du temps, je viens ici pour le plaisir. Ensuite, il y a des moments où je reçois accidentellement des idées profondes
slebetman


11

JavaScript (ES6), 34 octets

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

Ça reducedoit sûrement être mieux que map.


7

Python, 43 octets

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

Testez-le sur Ideone .


15
Non seulement Dennis nous bat tous solidement, mais il le fait en tout. unique. la langue.
DJMcMayhem

7

Gelée , 7 6 octets

Ṇ;żḅ@/

Essayez-le en ligne! ou vérifiez tous les cas de test .

Comment ça marche

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

PiPZ}N$X]

Cela utilise l'indexation basée sur 1 (désormais autorisée par le défi), ce qui est le choix naturel dans MATL.

Pour comparer avec les cas de test du défi, ajoutez 1à chaque entrée dans le vecteur d'index d'entrée et soustrayez 1de la sortie.

Essayez-le en ligne!

Explication

Le code est basé sur la X]fonction intégrée , qui convertit les indices multidimensionnels en un seul index linéaire (comme la sub2indfonction Matlab ou Octave ).

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 octets

4L)1hPYpP*s

Cela utilise une indexation basée sur 0, comme dans le défi d'origine.

Essayez-le en ligne!

Explication

Le code effectue explicitement les multiplications et ajouts requis.

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 octets

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

Je vais probablement me faire botter les fesses par les meilleurs golfeurs de python.


4

Python 3.5, 69

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

Testez ici


Bonne réponse! Beaucoup mieux que le mien.
DJMcMayhem

@DrGreenEggsandHamDJ J'ai volé la méthode eval de votre solution :)
Alexander Nigl

4

Haskell, 34 octets

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

Exemple d'utilisation: [10,10,4,62,7] # [1,2,3,4,5]-> 22167.

Comment ça marche:

      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 octets

Une macro rapide:

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

Utilisez comme:

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

Cela peut être un peu un abus des règles. Crée un tableau avec la taille donnée, puis vérifie pour voir dans quelle mesure les index donnés compensent le pointeur. Sorties vers STDOUT.

C'est tellement sale ... Mais j'adore le fait que cela soit valable.


3

Mathematica, 27 octets

#~FromDigits~MixedRadix@#2&

Une fonction sans nom qui prend la liste des indices comme premier argument et la liste des dimensions en second. Basé sur la même observation que la réponse APL de Dennis selon laquelle le calcul de l'indice n'est en réalité qu'une conversion à base mixte.


3

Octave, 58 54 octets

Merci à @AlexA. pour sa suggestion, qui a supprimé 4 octets

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

L'entrée et la sortie sont basées sur 1. Pour comparer avec les cas de test, ajoutez 1ot chaque entrée dans l'entrée et soustrayez 1de la sortie.

Il s'agit d'une fonction anonyme. Pour l'appeler, affectez-le à une variable.

Essayez-le ici .

Explication

Cela fonctionne en construisant en fait le tableau multidimensionnel ( reshape(...)), rempli de valeurs 1, 2... dans un ordre linéaire ( 1:prod(d)), puis l' indexation à l'indice multidimensionnel pour obtenir la valeur corrresponding.

L'indexation se fait en convertissant l'index multidimensionnel d'entrée ien un tableau de cellules ( num2cell(...)) puis en une liste séparée par des virgules ( {:}).

Les deux flipopérations sont nécessaires pour adapter l'ordre des dimensions de C à Octave.


pourquoi remodeler a une deuxième paire de parenthèses n'est pas non syntaxique?
Abr001am

@ Agawa001 Voulez-vous dire une deuxième paire après reshape ? C'est non syntaxique dans Matlab, mais accepté dans Octave. Cela fonctionne comme un index
Luis Mendo

oh Octave !! cela doit être meilleur et plus ergonomique que matlab, tha, ks pour l'illumination.
Abr001am

@ Agawa001 Il peut aussi conduire à une certaine confusion , bien que
Luis Mendo

Un conseil pour les fonctions anonymes dans l'exemple de code: j'utilise @(...) ...dans la première ligne de mon code, puis f = ans;dans la seconde. Cela rend la longueur de la première ligne égale au nombre d'octets à signaler.
bers

3

CJam, 7 octets

0q~z+:b

Essayez-le en ligne!

Comment ça marche

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.

Donnez-nous une chance, Dennis! : D
HyperNeutrino

2

Haskell, 47 octets

Deux solutions de longueur égale:

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

Appelé comme: ((sum.).s)[4,2][5,10].

Voici une version infixe:

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

2

Octave, 47 / 43 /31 octets

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

Testez-le ici .

Cela dit, comme cela a été demandé dans un commentaire , l'indexation basée sur 1 a été jugée correcte lorsque cela est naturel pour la langue utilisée. Dans ce cas, nous pouvons économiser 4 octets:

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

Par analogie, je soutiens que si l'objectif du code est d'indexer linéairement un tableau dans ce langage , le retournement complet et la prise en compte de l'ordre majeur de la colonne MATLAB / Octave ne devraient pas non plus être nécessaires. Dans ce cas, ma solution devient

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

Testez celui-là ici .


Bonjour et bienvenue chez PPCG! Très bonne réponse!
NoOneIsHere

1

Mathematica, 47 octets

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

(Unicode est U + F3C7, ou \[Transpose].) Pour cela, j'ai réécrit l'expression comme D n ( D n -1 (⋯ ( D 3 ( D 2 S 1 + S 2 ) + S 3 ) ⋯) + S n -1 ) + S n . Il suffit de Foldla fonction sur les deux listes.


1

En fait, 13 octets

;pX╗lr`╜tπ`M*

Essayez-le en ligne!

Ce programme prend la liste des indices comme première entrée et la liste des dimensions comme deuxième entrée.

Explication:

;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

Raquette 76 octets

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

Non golfé:

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

Essai:

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

Sortie:

42
22167
37

0

C #, 73 octets

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

Programme complet avec cas de test:

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 octets

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

Un golf plutôt naïf ici, vient d'écraser un sous anonyme.

Perl 6 a une variable d'état anonyme $qui est utile pour créer un compteur dans une boucle (par exemple, en utilisant post-incrémentation $++ou pré-incrémentation ++$). Je pré-incrémente cette variable d'état pour incrémenter l'index de départ de la tranche du tableau de dimensions à l'intérieur d'une carte.

Voici une fonction non golfée qui crée les sous-listes

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

Ensuite, il suffit de réduire les sous-listes avec l' ×opérateur multiplication ( ) et d'obtenir sumles résultats.

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 octets

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

Non golfé:

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 octets

-18 octets pour l'utilisation 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...);}};

Non golfé:

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, seulement fonctions, 116 octets

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

Non golfé:

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)
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.