Indice di un array multidimensionale


28

I linguaggi di livello inferiore, come C e C ++, in realtà non hanno alcun concetto di array multidimensionali. (Diversi da vettori e array dinamici) Quando si crea un array multidimensionale con

int foo[5][10];

Questo è in realtà solo zucchero sintattico . Quello che fa veramente C è creare un singolo array contiguo di 5 * 10 elementi. Questo

foo[4][2]

è anche zucchero sintattico. Questo si riferisce davvero all'elemento a

4 * 10 + 2

o, il 42 ° elemento. In generale, l'indice dell'elemento [a][b]nell'array foo[x][y]è a

a * y + b

Lo stesso concetto si applica alle matrici 3d. Se abbiamo foo[x][y][z]e accediamo a un elemento, [a][b][c]stiamo davvero accedendo a un elemento:

a * y * z + b * z + c

Questo concetto si applica alle matrici n- dimensionali. Se abbiamo un array con dimensioni D1, D2, D3 ... Dne accediamo all'elemento, S1, S2, S3 ... Snla formula è

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

La sfida

È necessario scrivere un programma o una funzione che calcola l'indice di un array multidimensionale secondo la formula sopra. L'input sarà di due array. Il primo array è rappresentato dalle dimensioni e il secondo array è rappresentato dagli indici. La lunghezza di questi due array sarà sempre uguale e almeno 1.

Puoi tranquillamente supporre che ogni numero negli array sarà un numero intero non negativo. Puoi anche supporre che non otterrai un 0array nella dimensione, sebbene a 0 possa essere negli indici. Puoi anche supporre che gli indici non saranno più grandi delle dimensioni.

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
Quindi questo è l'indicizzazione basato su 0, giusto? Possiamo utilizzare l'indicizzazione basata su 1 se è più naturale per la nostra lingua preferita?
Alex A.

@AlexA. Sì, è accettabile.
DJMcMayhem

11
In realtà, ciò che C "fa veramente" è creare un singolo array contiguo di cinque elementi di tipo int[10].


1
@Hurkyl Sì, ma tutti i numeri interi in quell'array sono ancora contigui. È solo semantica.
DJMcMayhem

Risposte:


60

APL, 1 byte

Provalo su TryAPL .


21
Bene, tutto qui. Abbiamo un vincitore. Tutti gli altri possono andare a casa ora.
DJMcMayhem

3
Perché ... perché funziona? o_O
Alex A.

10
@AlexA. L'indicizzazione di un array multidimensionale è essenzialmente una conversione di base mista.
Dennis,

21
Oh, guarda, un buco in uno mentre giochi a golf!
Fondi Monica's Lawsuit,

8
Il più delle volte vengo qui per divertimento. Poi ci sono momenti in cui per sbaglio ricevo intuizioni profonde
slebetman,


11

JavaScript (ES6), 34 byte

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

Sicuramente reducedeve essere migliore di map.


7

Python, 43 byte

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

Provalo su Ideone .


15
Non solo Dennis ci mette alla prova, ma lo fa in tutti. singolo. linguaggio.
DJMcMayhem

7

Gelatina , 7 6 byte

Ṇ;żḅ@/

Provalo online! o verifica tutti i casi di test .

Come funziona

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

Questo utilizza l'indicizzazione basata su 1 (ora consentita dalla sfida), che è la scelta naturale in MATL.

Per confrontare i casi di test nella sfida, aggiungere 1a ciascuna voce nel vettore indice di input e sottrarre 1dall'output.

Provalo online!

Spiegazione

Il codice si basa sulla X]funzione incorporata , che converte gli indici multidimensionali in un singolo indice lineare (come Matlab o la sub2indfunzione di Ottava ).

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

Questo utilizza l'indicizzazione basata su 0, come nella sfida originale.

Provalo online!

Spiegazione

Il codice esegue esplicitamente le moltiplicazioni e le aggiunte richieste.

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

Probabilmente mi farò prendere a calci nel culo dai migliori golfisti di pitone.


4

Python 3.5, 69

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

Prova qui


Bella risposta! Molto meglio del mio.
DJMcMayhem

@DrGreenEggsandHamDJ Ho rubato il metodo eval dalla tua soluzione :)
Alexander Nigl,

4

Haskell, 34 byte

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

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

Come funziona:

      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

Una macro veloce:

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

Usa come:

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

Questo potrebbe essere un po 'un abuso delle regole. Crea un array con le dimensioni indicate, quindi controlla per vedere fino a che punto gli indici dati compensano il puntatore. Uscita su STDOUT.

Sembra così sporco ... Ma adoro il fatto che sia valido.


3

Mathematica, 27 byte

#~FromDigits~MixedRadix@#2&

Una funzione senza nome che accetta l'elenco di indici come primo argomento e l'elenco di dimensioni secondo. Sulla base della stessa osservazione della risposta APL di Dennis, il calcolo dell'indice è in realtà solo una conversione a base mista.


3

Ottava, 58 54 byte

Grazie a @AlexA. per il suo suggerimento, che ha rimosso 4 byte

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

Input e output sono basati su 1. Per confrontare con i casi di test, aggiungere 1ot ogni voce nell'input e sottrarre 1dall'output.

Questa è una funzione anonima. Per chiamarlo, assegnarlo a una variabile.

Provalo qui .

Spiegazione

Funziona realizzando la matrice multidimensionale ( reshape(...)), piena di valori 1, 2... in ordine lineare ( 1:prod(d)), e quindi indicizzando con l'indice multidimensionale per ottenere il valore corrispondente.

L'indicizzazione viene eseguita convertendo l'indice multidimensionale di input iin un array di celle ( num2cell(...)) e quindi in un elenco separato da virgole ( {:}).

Le due flipoperazioni sono necessarie per adattare l'ordine delle dimensioni da C a Ottava.


perché la risagoma ha una seconda coppia di parentesi non così sintattica?
Abr001,

@ Agawa001 Intendi una seconda coppia dopo reshape ? Questo non è sintattico in Matlab, ma accettato in Octave. Funziona come un indice
Luis Mendo,

oh Octave !! quello deve essere migliore e più ergonomico di matlab, tha, ks per l'illuminazione.
Abr001,

@ Agawa001 Si può anche portare a una certa confusione , anche se
Luis Mendo

Un suggerimento per le funzioni anonime nel codice di esempio: lo uso @(...) ...nella prima riga del mio codice, seguito dal f = ans;secondo. Ciò rende la lunghezza della prima riga uguale al numero di byte da segnalare.
bers

3

CJam, 7 byte

0q~z+:b

Provalo online!

Come funziona

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.

Dacci una possibilità, Dennis! : D
HyperNeutrino,

2

Haskell, 47 byte

Due soluzioni di uguale lunghezza:

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

Chiamato come: ((sum.).s)[4,2][5,10].

Ecco una versione infix:

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

2

Ottava, 47 / 43 /31 byte

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

Provalo qui .

Detto questo, come è stato chiesto in un commento , l'indicizzazione basata su 1 è stata dichiarata OK quando questo è naturale per la lingua utilizzata. In questo caso, possiamo salvare 4 byte:

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

In analogia, sostengo che se l'obiettivo del codice è di indicizzare linearmente un array all'interno di quel linguaggio , anche l'intero capovolgimento e la contabilizzazione dell'ordine principale della colonna MATLAB / Octave non dovrebbero essere necessari. In tal caso, la mia soluzione diventa

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

Prova quello qui .


Ciao e benvenuto in PPCG! Bella risposta!
NoOneIsHere

1

Mathematica, 47 byte

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

(Unicode è U + F3C7 o \[Transpose].) Per questo, ho riscritto l'espressione come D n ( D n -1 (⋯ ( D 3 ( D 2 S 1 + S 2 ) + S 3 ) ⋯) + S n -1 ) + S n . È solo Foldla funzione su entrambi gli elenchi.


1

In realtà, 13 byte

;pX╗lr`╜tπ`M*

Provalo online!

Questo programma accetta l'elenco di indici come primo input e l'elenco di dimensioni come secondo input.

Spiegazione:

;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

Racchetta 76 byte

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

test:

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

Produzione:

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

Programma completo con casi di 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 byte

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

Un golf piuttosto ingenuo qui, appena schiacciato un sub anonimo.

Perl 6 ha una variabile di stato anonima $che è utile per creare un contatore in un ciclo (ad esempio, usando post-incremento $++o pre-incremento ++$). Pre-incremento questa variabile di stato per incrementare l'indice iniziale della porzione di array di dimensioni all'interno di una mappa.

Ecco una funzione non golfata che crea le liste secondarie

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

Quindi si tratta solo di ridurre gli elenchi secondari con l' ×operatore moltiplicazione ( ) e di suminserire i risultati.

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}

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 byte

-18 byte per l'utilizzo 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
 }
};

Uso:

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

Alternativa, solo funzioni, 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...);};}

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

Uso:

f(5,10)(4,2)
f(10,10,10)(4,3,2)
f(10,10,4,62,7)(1,2,3,4,5)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.