Índice de uma matriz multidimensional


28

Linguagens de nível inferior, como C e C ++, na verdade não têm conceito de matrizes multidimensionais. (Diferente de vetores e matrizes dinâmicas) Quando você cria uma matriz multidimensional com

int foo[5][10];

Na verdade, isso é apenas açúcar sintático . O que C realmente faz é criar uma única matriz contígua de 5 * 10 elementos. este

foo[4][2]

também é açúcar sintático. Isso realmente se refere ao elemento em

4 * 10 + 2

ou o 42º elemento. Em geral, o índice do elemento [a][b]na matriz foo[x][y]está em

a * y + b

O mesmo conceito se aplica às matrizes 3D. Se temos foo[x][y][z]e acessamos o elemento [a][b][c], estamos realmente acessando o elemento:

a * y * z + b * z + c

Esse conceito se aplica a matrizes n- dimensionais. Se temos uma matriz com dimensões D1, D2, D3 ... Dne acessamos S1, S2, S3 ... Sno elemento, a fórmula é

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

O desafio

Você deve escrever um programa ou função que calcule o índice de uma matriz multidimensional de acordo com a fórmula acima. A entrada terá duas matrizes. A primeira matriz são as dimensões e a segunda matriz são os índices. O comprimento dessas duas matrizes sempre será igual e pelo menos 1.

Você pode assumir com segurança que todo número nas matrizes será um número inteiro não negativo. Você também pode assumir que não obterá um 0na matriz de dimensões, embora um 0 possa estar nos índices. Você também pode assumir que os índices não serão maiores que as dimensões.

Teste de E / S

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
Portanto, essa indexação é baseada em 0, correto? Podemos usar a indexação baseada em 1 se isso for mais natural para o nosso idioma preferido?
Alex A.

@AlexA. Sim, isso é aceitável.
DJMcMayhem

11
Na verdade, o que C 'realmente faz' é criar uma única matriz contígua de cinco elementos do tipo int[10].


1
@Hurkyl Sim, mas todos os números inteiros nessa matriz ainda são contíguos. É apenas semântica.
DJMcMayhem

Respostas:


60

APL, 1 byte

Teste-o no TryAPL .


21
Bem, é isso. Temos um vencedor. Todos os outros podem ir para casa agora.
DJMcMayhem

3
Por que ... por que isso funciona? o_O
Alex A.

10
@AlexA. A indexação de uma matriz multidimensional é essencialmente uma conversão de base mista.
Dennis

21
Oh, olhe, um buraco em um enquanto jogava golfe!
Fund Monica's Lawsuit

8
Na maioria das vezes eu venho aqui por diversão. Depois, há momentos em que eu acidentalmente receber profundas percepções
slebetman


11

JavaScript (ES6), 34 bytes

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

Certamente reducedeve ser melhor que map.


7

Python, 43 bytes

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

Teste em Ideone .


15
Dennis não apenas solta todos nós, mas ele faz isso em todos. solteiro. língua.
DJMcMayhem

7

Geléia , 7 6 bytes

Ṇ;żḅ@/

Experimente online! ou verifique todos os casos de teste .

Como 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]

Isso usa a indexação baseada em 1 (agora permitida pelo desafio), que é a escolha natural no MATL.

Para comparar com os casos de teste no desafio, inclua 1em cada entrada no vetor de índice de entrada e subtraia 1da saída.

Experimente online!

Explicação

O código é baseado na X]função interna , que converte índices multidimensionais em um único índice linear (como a sub2indfunção 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 bytes

4L)1hPYpP*s

Isso usa indexação baseada em 0, como no desafio original.

Experimente online!

Explicação

O código faz explicitamente as multiplicações e adições necessárias.

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

Provavelmente vou ser chutado pelos melhores jogadores de python por aí.



4

Haskell, 34 bytes

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

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

Como 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

Uma macro rápida:

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

Use como:

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

Isso pode ser um pouco de abuso das regras. Cria uma matriz com o tamanho especificado, em seguida, verifica se a distância em que os índices determinados compensa o ponteiro. Saídas para STDOUT.

Isso parece tão sujo ... Mas eu simplesmente amo o fato de que isso é válido.


3

Mathematica, 27 bytes

#~FromDigits~MixedRadix@#2&

Uma função sem nome que leva a lista de índices como o primeiro argumento e a lista de dimensões em segundo. Com base na mesma observação da resposta de Dennis à APL de que calcular o índice é realmente apenas uma conversão de base mista.


3

Oitava, 58 54 bytes

Graças a @AlexA. por sua sugestão, que removeu 4 bytes

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

Entrada e saída são baseadas em 1. Para comparar com os casos de teste, adicione1 cada entrada na entrada e subtraia 1da saída.

Esta é uma função anônima. Para chamá-lo, atribua-o a uma variável.

Experimente aqui .

Explicação

Isso funciona, realmente construir a matriz multidimensional ( reshape(...)), cheio de valores 1, 2... de modo linear (1:prod(d) ), e depois indexando com o índice multidimensional para obter pelo valor correspondente.

A indexação é feita convertendo o índice multidimensional de entrada iem uma matriz de células ( num2cell(...)) e depois em uma lista separada por vírgula ({:} ).

As duas flipoperações são necessárias para adaptar a ordem das dimensões de C para oitava.


por que remodelar tem um segundo par de parênteses não é não sintático?
Abr001am

@ Agawa001 Você quer dizer um segundo par depois reshape ? Isso não é sintático no Matlab, mas é aceito no Octave. Funciona como um índice
Luis Mendo

oh oitava !! isso deve ser melhor e mais ergonômico que o matlab, ou seja, para a iluminação.
Abr001am

@ Agawa001 Ele também pode levar a alguma confusão , embora
Luis Mendo

Uma dica para funções anônimas no código de exemplo: eu uso @(...) ...na primeira linha do meu código, seguida pela f = ans;segunda. Isso torna o comprimento da primeira linha igual ao número de bytes a serem relatados.
BERS

3

CJam, 7 bytes

0q~z+:b

Experimente online!

Como 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.

Nos dê uma chance, Dennis! : D
HyperNeutrino

2

Haskell, 47 bytes

Duas soluções de igual comprimento:

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

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

Aqui está uma versão infix:

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

2

Oitava, 47 / 43 /31 bytes

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

Teste aqui .

Dito isto, como foi solicitado em um comentário , a indexação baseada em 1 foi considerada boa quando isso é natural para o idioma que está sendo usado. Nesse caso, podemos salvar 4 bytes:

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

Por analogia, argumento que, se o objetivo do código é indexar linearmente uma matriz dentro dessa linguagem , todo o movimento e contabilização da ordem principal da coluna do MATLAB / Octave também não seria necessário. Nesse caso, minha solução se torna

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

Teste esse aqui .


Olá, e bem-vindo ao PPCG! Ótima resposta!
NoOneIsHere

1

Mathematica, 47 bytes

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

(Unicode é U + F3C7, ou \[Transpose].) Para isso, reescrevi a expressão como D n ( D n -1 (⋯ ( D 3 ( D 2 S 1 + S 2 ) + S 3 ) ⋯) + S n -1 ) + S n . É apenas Folda função nas duas listas.


1

Na verdade, 13 bytes

;pX╗lr`╜tπ`M*

Experimente online!

Este programa utiliza a lista de índices como a primeira entrada e a lista de dimensões como a segunda entrada.

Explicação:

;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

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

Teste:

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

Saída:

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 com casos de teste:

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[++$ ..*]}}

Um golfe bastante ingênuo aqui, acabou de esmagar um sub anônimo.

O Perl 6 tem uma variável de estado anônima $que é útil para criar um contador em um loop (por exemplo, usando pós-incremento $++ou pré-incremento++$ ). Eu pré-incremento essa variável de estado para incrementar o índice inicial da fatia da matriz de dimensão dentro de um mapa.

Aqui está uma função não destruída que cria as sub-listas

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

Depois, basta reduzir as sub-listas com o ×operador multiplication ( ) e obter sumos 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}

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

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, apenas funções, 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...);
  };
}

Uso:

f(5,10)(4,2)
f(10,10,10)(4,3,2)
f(10,10,4,62,7)(1,2,3,4,5)
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.