Индекс многомерного массива


28

Языки более низкого уровня, такие как C и C ++, фактически не имеют понятия многомерных массивов. (Кроме векторов и динамических массивов) При создании многомерного массива с

int foo[5][10];

Это на самом деле просто синтаксический сахар . Что на самом деле делает С, так это создает единый непрерывный массив 5 * 10 элементов. это

foo[4][2]

также синтаксический сахар. Это действительно относится к элементу в

4 * 10 + 2

или 42-й элемент. В общем, индекс элемента [a][b]в массивеfoo[x][y] равен

a * y + b

То же самое относится и к 3D-массивам. Если у нас есть, foo[x][y][z]и мы получаем доступ к элементу[a][b][c] мы действительно к элементу:

a * y * z + b * z + c

Эта концепция применима к n- мерным массивам. Если у нас есть массив с измерениями, D1, D2, D3 ... Dnи мы получаем доступ к элементу, S1, S2, S3 ... Snформула

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

Соревнование

Вы должны написать программу или функцию, которая вычисляет индекс многомерного массива в соответствии с формулой выше. На вход будет два массива. Первый массив - это размеры, а второй - индексы. Длина этих двух массивов всегда будет равна и не меньше 1.

Вы можете смело предполагать, что каждое число в массивах будет неотрицательным целым числом. Вы также можете предположить, что вы не получите a 0в массиве измерений, хотя 0 может быть в индексах. Также можно предположить, что индексы не будут больше размеров.

Тест 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
Так что это индексирование на основе 0, верно? Можем ли мы использовать индексирование на основе 1, если это более естественно для нашего языка?
Алекс А.

@AlexA. Да, это приемлемо
DJMcMayhem

11
На самом деле то, что в действительности делает C, - это создание единого непрерывного массива из пяти элементов типа int[10].


1
@Hurkyl Да, но все целые числа в этом массиве все еще смежные. Это просто семантика.
DJMcMayhem

Ответы:


60

APL, 1 байт

Проверьте это на TryAPL .


21
Ну вот и все. У нас есть победитель. Все остальные могут идти домой сейчас.
DJMcMayhem

3
Почему ... почему это работает? о_О
Алекс А.

10
@AlexA. Индексация многомерного массива по сути является смешанным базовым преобразованием.
Денис

21
О, смотри, дыра в одном во время игры в гольф!
Фонд Моники Иск

8
Большую часть времени я прихожу сюда ради удовольствия. Тогда бывают случаи, когда я случайно получаю глубокое понимание
slebetman


11

JavaScript (ES6), 34 байта

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

Конечно, reduceдолжно быть лучше, чем map.


7

Python, 43 байта

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

Проверьте это на Ideone .


15
Деннис не только одолел всех нас, но и сделал это в каждом. не замужем. язык.
DJMcMayhem

7

Желе , 7 6 байт

Ṇ;żḅ@/

Попробуйте онлайн! или проверьте все тесты .

Как это работает

Ṇ;żḅ@/  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 байт

PiPZ}N$X]

При этом используется индексирование на основе 1 (теперь это разрешено задачей), что является естественным выбором в MATL.

Чтобы сравнить с тестовыми примерами в задании, добавьте 1к каждой записи во входном индексе вектор и вычтите 1из выходных данных.

Попробуйте онлайн!

объяснение

Код основан на встроенной X]функции, которая преобразует многомерные индексы в один линейный индекс (например, sub2indфункцию Matlab или 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 байт

4L)1hPYpP*s

При этом используется индексирование на основе 0, как в исходной задаче.

Попробуйте онлайн!

объяснение

Код явно делает необходимые умножения и сложения.

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 байт

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

Я, вероятно, получу удовольствие от лучших игроков в гольф на питоне.



4

Haskell, 34 байта

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

Пример использования: [10,10,4,62,7] # [1,2,3,4,5]-> 22167.

Как это работает:

      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 байт

Быстрый макрос:

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

Используйте как:

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

Это может быть немного злоупотреблением правилами. Создает массив с заданным размером, затем проверяет, насколько далеко заданные индексы смещают указатель. Выходы в STDOUT.

Это так грязно ... Но мне просто нравится тот факт, что это действительно.


3

Mathematica, 27 байт

#~FromDigits~MixedRadix@#2&

Безымянная функция, которая принимает список индексов в качестве первого аргумента, а список измерений - второй. Основываясь на том же наблюдении, что и ответ Денниса APL, вычисление индекса на самом деле является просто смешанным преобразованием.


3

Октава, 58 54 байта

Спасибо @AlexA. за его предложение, которое удалило 4 байта

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

Вход и выход основаны на 1. Для сравнения с тестовыми примерами добавьте 1каждую запись во входные данные и вычтите 1из выходных данных.

Это анонимная функция. Чтобы вызвать его, присвойте его переменной.

Попробуй здесь .

объяснение

Это работает на самом деле построение многомерного массива ( reshape(...)), заполненные значения 1, 2... в линейном порядке (1:prod(d) ), а затем индексации с помощью многомерного индекса, чтобы получить соответствующее значение.

Индексация выполняется путем преобразования входного многомерного индекса iв массив ячеек ( num2cell(...)), а затем в список через запятую ({:} ).

Две flipоперации необходимы для адаптации порядка размеров от C до Octave.


почему у reshape есть вторая пара круглых скобок, разве это не синтаксическое?
Abr001am

@ Agawa001 Вы имеете в виду вторую пару после reshape ? Это не синтаксическое в Matlab, но принято в Octave. Он работает в качестве индекса
Луис Мендо

о октава !! это должно быть лучше и более эргономично, чем matlab, tha, ks для просветления.
Abr001am

@ Agawa001 Это также может привести к некоторой путанице ,
Луис Мендо

Совет для анонимных функций в примере кода: я использую @(...) ...в первой строке своего кода, а затем f = ans;во второй. Это делает длину первой строки равной количеству байтов для отчета.
берс

3

CJam, 7 байтов

0q~z+:b

Попробуйте онлайн!

Как это работает

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.

Дай нам шанс, Деннис! : D
HyperNeutrino

2

Haskell, 47 байтов

Два решения одинаковой длины:

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

Вызывается , как: ((sum.).s)[4,2][5,10].

Вот инфиксная версия:

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

2

Октава, 47 / 43 /31 байт

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

Проверьте это здесь .

Сказав, что, как это было сказано в комментарии , индексирование на основе 1 считается нормальным, когда это естественно для используемого языка. В этом случае мы можем сохранить 4 байта:

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

По аналогии, я утверждаю, что если целью кода является линейное индексирование массива в пределах этого языка , то переворачивание целого и учет главного порядка столбцов MATLAB / Octave также не должны быть необходимыми. В этом случае мое решение становится

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

Проверьте это здесь .


Здравствуйте и добро пожаловать в PPCG! Отличный ответ!
NoOneIsHere

1

Mathematica, 47 байт

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

(Unicode - это U + F3C7 или \[Transpose].) Для этого я переписал выражение как D n ( D n -1 (⋯ ( D 3 ( D 2 S 1 + S 2 ) + S 3 ) ⋯) + S n -1 ) + S n . Просто Foldс функцией над обоими списками.


1

На самом деле, 13 байтов

;pX╗lr`╜tπ`M*

Попробуйте онлайн!

Эта программа принимает список индексов в качестве первого ввода и список измерений в качестве второго ввода.

Объяснение:

;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

Ракетка 76 байт

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

Тестирование:

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

Выход:

42
22167
37

0

C #, 73 байта

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

Полная программа с тестовыми примерами:

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 байт

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

Здесь довольно наивный гольф, только что раздавленный анонимный саб.

Perl 6 имеет анонимную переменную состояния, $которая полезна для создания счетчика в цикле (например, с использованием постинкремента $++или предварительного инкремента++$ ). Я предварительно увеличиваю эту переменную состояния, чтобы увеличить начальный индекс фрагмента массива измерений внутри карты.

Вот функция ungolfed, которая создает подсписки

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

Тогда нужно просто сократить подсписки с помощью ×оператора multiplication ( ) и получить sumрезультаты.

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 байт

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

С ++ 17, 133 115 байт

-18 байт для использования 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
 }
};

Использование:

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

Альтернатива, только функции, 116 байт

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

Использование:

f(5,10)(4,2)
f(10,10,10)(4,3,2)
f(10,10,4,62,7)(1,2,3,4,5)
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.