Індекс багатовимірного масиву


28

Мови нижчого рівня, такі як C і C ++, насправді не мають поняття багатовимірних масивів. (Окрім векторів та динамічних масивів) Коли ви створюєте багатовимірний масив із

int foo[5][10];

Це насправді просто синтаксичний цукор . Що насправді робить C, це створити єдиний суміжний масив з 5 * 10 елементів. Це

foo[4][2]

також є синтаксичним цукром. Це дійсно стосується елемента at

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.

Можна сміливо припускати, що кожне число масивів буде невід'ємним цілим числом. Ви також можете припустити, що ви не отримаєте 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
Чому ... чому це працює? o_O
Олексій А.

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

21
О, дивіться, дірка в одному під час гольфу!
Фонд позову Моніки

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


11

JavaScript (ES6), 34 байти

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

Безумовно, reduceмає бути краще, ніж map.


7

Пітон, 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

Пітон, 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

Хаскелл, 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

Математика, 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)), а потім індексувати з багатовимірним індексом , щоб отримати corrresponding значення.

Індексація проводиться шляхом перетворення вхідного багатовимірного індексу iв масив комірок ( num2cell(...)), а потім у список, розділений комами ( {:}).

Дві flipоперації необхідні для адаптації порядку розмірів від C до Октави.


Чому переформатування має другу пару дужок, що не синтаксичне?
Abr001am

@ Agawa001 Ви маєте на увазі другу пару після reshape ? Це не синтаксично в Matlab, але прийнято в Octave. Він працює як індекс
Луїс Мендо

о Октава !! це повинно бути кращим і ергономічнішим, ніж матлаб, тха, кс для просвітлення.
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

Математика, 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)))))))

Безголівки:

(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 має анонімну змінну стану, $яка корисна для створення лічильника в циклі (наприклад, за допомогою пост-збільшення $++або попереднього збільшення ++$). Я попередньо збільшив цю змінну стану, щоб збільшити початковий індекс фрагмента масиву розмірів всередині карти.

Ось така функція, яка не використовується для створення піддослідників

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

Тоді лише питання скорочення підсписів за допомогою ×оператора множення ( ) та 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}

Безголівки:

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

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

Безголівки:

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

Безголівки:

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.