Índice de una matriz multidimensional


28

Los lenguajes de nivel inferior, como C y C ++, en realidad no tienen el concepto de matrices multidimensionales. (Aparte de vectores y matrices dinámicas) Cuando crea una matriz multidimensional con

int foo[5][10];

En realidad, esto es solo azúcar sintáctico . Lo que C realmente hace es crear una única matriz contigua de 5 * 10 elementos. Esta

foo[4][2]

También es azúcar sintáctico. Esto realmente se refiere al elemento en

4 * 10 + 2

o, el elemento 42. En general, el índice del elemento [a][b]en la matriz foo[x][y]está en

a * y + b

El mismo concepto se aplica a las matrices 3d. Si tenemos foo[x][y][z]y accedemos al elemento [a][b][c], realmente estamos accediendo al elemento:

a * y * z + b * z + c

Este concepto se aplica a matrices n- dimensionales. Si tenemos una matriz con dimensiones D1, D2, D3 ... Dny accedemos al elemento, S1, S2, S3 ... Snla fórmula es

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

El reto

Debe escribir un programa o función que calcule el índice de una matriz multidimensional de acuerdo con la fórmula anterior. La entrada será de dos matrices. La primera matriz son las dimensiones, y la segunda matriz son los índices. La longitud de estas dos matrices siempre será igual y al menos 1.

Puede asumir con seguridad que cada número en las matrices será un número entero no negativo. También puede suponer que no obtendrá un 0en la matriz de dimensiones, aunque 0 podría estar en los índices. También puede suponer que los índices no serán más grandes que las dimensiones.

Prueba 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

44
Entonces esta es una indexación basada en 0, ¿correcto? ¿Podemos usar la indexación basada en 1 si eso es más natural para nuestro idioma de elección?
Alex A.

@AlexA. Si, eso es aceptable.
DJMcMayhem

11
En realidad, lo que C 'realmente hace' es crear una única matriz contigua de cinco elementos de tipo int[10].


1
@Hurkyl Sí, pero todos los enteros de esa matriz siguen siendo contiguos. Es solo semántica.
DJMcMayhem

Respuestas:


60

APL, 1 byte

Pruébelo en TryAPL .


21
Bueno, eso es todo. Tenemos un ganador. Todos los demás pueden irse a casa ahora.
DJMcMayhem

3
¿Por qué ... por qué funciona esto? o_O
Alex A.

10
@AlexA. La indexación de una matriz multidimensional es esencialmente una conversión de base mixta.
Dennis

21
¡Oh, mira, un hoyo en uno mientras juegas al golf!
Financia la demanda de Mónica

8
La mayoría de las veces vengo aquí por diversión. A continuación, hay momentos en los que accidentalmente recibo profundas penetraciones
slebetman


11

JavaScript (ES6), 34 bytes

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

Seguramente reducedebe ser mejor que map.


7

Python, 43 bytes

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

Pruébalo en Ideone .


15
Dennis no solo nos golpea sólidamente a todos, sino que lo hace en todos. soltero. idioma.
DJMcMayhem

7

Gelatina , 7 6 bytes

Ṇ;żḅ@/

Pruébalo en línea! o verificar todos los casos de prueba .

Cómo funciona

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

PiPZ}N$X]

Utiliza la indexación basada en 1 (ahora permitida por el desafío), que es la opción natural en MATL.

Para comparar con los casos de prueba en el desafío, agregue 1a cada entrada en el vector de índice de entrada y reste 1de la salida.

Pruébalo en línea!

Explicación

El código se basa en la X]función incorporada , que convierte los índices multidimensionales en un único índice lineal (como la sub2indfunción de Matlab u 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 bytes

4L)1hPYpP*s

Esto usa indexación basada en 0, como en el desafío original.

Pruébalo en línea!

Explicación

El código hace explícitamente las multiplicaciones y adiciones requeridas.

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

Probablemente me patearán el trasero los mejores golfistas de python.



4

Haskell, 34 bytes

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

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

Cómo funciona:

      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 bytes

Una macro rápida:

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

Usar como:

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

Esto puede ser un poco un abuso de las reglas. Crea una matriz con el tamaño dado, que comprueba hasta qué punto los índices dados compensan el puntero. Salidas a STDOUT.

Esto se siente tan sucio ... Pero me encanta el hecho de que esto es válido.


3

Mathematica, 27 bytes

#~FromDigits~MixedRadix@#2&

Una función sin nombre que toma la lista de índices como primer argumento y la lista de dimensiones segundo. Basado en la misma observación que la respuesta APL de Dennis de que calcular el índice es realmente solo una conversión de base mixta.


3

Octava, 58 54 bytes

Gracias a @AlexA. por su sugerencia, que eliminó 4 bytes

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

La entrada y la salida están basadas en 1. Para comparar con los casos de prueba, agregue 1ot cada entrada en la entrada y reste 1de la salida.

Esta es una función anónima. Para llamarlo, asígnelo a una variable.

Probar aquí .

Explicación

Esto funciona en realidad la construcción de la matriz multidimensional ( reshape(...)), lleno de valores 1, 2... en orden lineal (1:prod(d) ), y luego indexando con el índice multidimensional para obtener el valor correspondiente.

La indexación se realiza convirtiendo el índice multidimensional de entrada ien una matriz de celdas ( num2cell(...)) y luego en una lista separada por comas ( {:}).

Las dos flipoperaciones son necesarias para adaptar el orden de dimensiones de C a Octave.


¿Por qué la remodelación tiene un segundo par de paréntesis que no es sintáctico?
Abr001am

@ Agawa001 ¿Te refieres a un segundo par después reshape ? Eso no es sintáctico en Matlab, pero se acepta en Octave. Funciona como un índice
Luis Mendo

oh octava !! eso debe ser mejor y más ergonómico que matlab, tha, ks para la iluminación.
Abr001am

@ Agawa001 También puede dar lugar a cierta confusión , aunque
Luis Mendo

Un consejo para funciones anónimas en el código de ejemplo: lo uso @(...) ...en la primera línea de mi código, seguido por f = ans;la segunda. Esto hace que la longitud de la primera línea sea igual al número de bytes a reportar.
Bers

3

CJam, 7 bytes

0q~z+:b

Pruébalo en línea!

Cómo funciona

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.

¡Danos una oportunidad, Dennis! : D
HyperNeutrino

2

Haskell, 47 bytes

Dos soluciones de igual longitud:

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

Llamado como: ((sum.).s)[4,2][5,10].

Aquí hay una versión infija:

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

2

Octava, 47 / 43 /31 bytes

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

Pruébalo aquí .

Dicho esto, como se preguntó en un comentario , se dijo que la indexación basada en 1 estaba bien cuando esto es natural para el lenguaje que se está utilizando. En este caso, podemos guardar 4 bytes:

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

En analogía, sostengo que si el objetivo del código es indexar linealmente una matriz dentro de ese lenguaje , tampoco debería ser necesario dar la vuelta y dar cuenta del orden principal de la columna de MATLAB / Octave. En ese caso, mi solución se convierte

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

Prueba esa aquí .


Hola y bienvenidos a PPCG! ¡Gran respuesta!
NoOneIsHere

1

Mathematica, 47 bytes

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

(Unicode es U + F3C7, o \[Transpose].) Para esto, reescribí la expresión como D n ( D n -1 (⋯ ( D 3 ( D 2 S 1 + S 2 ) + S 3 ) ⋯) + S n -1 ) + S n . Simplemente Folds la función sobre ambas listas.


1

En realidad, 13 bytes

;pX╗lr`╜tπ`M*

Pruébalo en línea!

Este programa toma la lista de índices como la primera entrada y la lista de dimensiones como la segunda entrada.

Explicación:

;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

Raqueta 76 bytes

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

Sin golf:

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

Pruebas:

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

Salida:

42
22167
37

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

Programa completo con casos de prueba:

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 bytes

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

Un golf bastante ingenuo aquí, simplemente aplastó a un submarino anónimo.

Perl 6 tiene una variable de estado anónimo $que es útil para crear un contador en un bucle (por ejemplo, usando un incremento posterior $++o un incremento previo ++$). Pre-incrementé esta variable de estado para incrementar el índice inicial del segmento de matriz de dimensión dentro de un mapa.

Aquí hay una función no protegida que crea las sublistas

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

Entonces es solo una cuestión de reducir las sublistas con el ×operador multiplication ( ), y obtener sumlos resultados.

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 bytes

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

Sin 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 bytes

-18 bytes para usar 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...);}};

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

Uso:

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

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

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

Uso:

f(5,10)(4,2)
f(10,10,10)(4,3,2)
f(10,10,4,62,7)(1,2,3,4,5)
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.