多次元配列のインデックス


28

CやC ++などの低レベル言語には、実際には多次元配列の概念がありません。(ベクトルと動的配列以外)で多次元配列を作成する場合

int foo[5][10];

これは実際には単なる構文糖です。Cが実際に行うのは、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

チャレンジ

上記の式に従って多次元配列のインデックスを計算するプログラムまたは関数を作成する必要があります。入力は2つの配列になります。最初の配列は次元であり、2番目の配列はインデックスです。これら2つの配列の長さは常に等しく、少なくとも1です。

配列内のすべての数値は負でない整数であると安全に仮定できます。また、インデックスには0a 0 が含まれている可能性ありますが、次元配列にはaを取得しないと想定できます。また、インデックスが次元よりも大きくないと仮定することもできます。

テスト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ベースのインデックスを使用できますか?
アレックスA.

@AlexA。はい、それは受け入れられます。
DJMcMayhem

11
実際、Cが「実際に」行うのは、typeの5つの要素の単一の連続した配列を作成することint[10]です。


1
@Hurkylはい、ただしその配列内の整数はすべて連続しています。ただのセマンティクスです。
DJMcMayhem

回答:


60

APL、1バイト

TryAPLでテストします


21
まあ、それだけです。勝者がいます。他の誰もが今家に帰ることができます。
DJMcMayhem

3
なぜ...なぜこれが機能するのですか?o_O
アレックスA.

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]

これは、MATLで自然な選択である1ベースのインデックス付け(チャレンジで許可されました)を使用します。

チャレンジのテストケースと比較するには1、入力インデックスベクトルの各エントリに追加し1、出力から減算します。

オンラインでお試しください!

説明

コードは組み込みX]関数に基づいており、多次元インデックスを単一の線形インデックス(MatlabやOctaveのsub2ind関数など)に変換します。

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&

最初の引数としてインデックスのリストを取り、2番目の次元のリストを取る名前のない関数。デニスのAPL回答と同じ観察に基づいて、インデックスの計算は実際には混合ベースの変換にすぎません。


3

オクターブ、58 54バイト

@AlexAに感謝します。4バイトを削除した彼の提案に対して

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

入力と出力は1ベースです。テストケースと比較するには1、入力の各エントリを追加1し、出力から減算します。

これは匿名関数です。呼び出すには、変数に割り当てます。

ここで試してみてください

説明

実際には多次元配列(構築することにより、これが作品reshape(...)の値でいっぱいに)、 12、...線形順序で(1:prod(d))した後、corrresponding値を取得するために、多次元インデックスとインデックス作成。

インデックス付けは、入力多次元インデックスiをセル配列(num2cell(...))に変換し、次にコンマ区切りリスト({:})に変換することにより行われます。

flipCからOctaveへの次元の順序を調整するには、2つの操作が必要です。


なぜreshapeには2組目の括弧があり、それが非構文的ではないのですか?
Abr001am

@ Agawa001 あと 2番目のペアreshapeですか?Matlabでは構文的ではありませんが、Octaveでは受け入れられています。インデックスとして機能します
ルイスメンドー

オクターブ!! それは、matlab、tha、ks、啓発よりも優れた人間工学的である必要があります。
-Abr001am

Agawa001 @それはまたにつながることができますいくつかの混乱が、
ルイス・Mendo

サンプルコードでの匿名関数のヒント:コード@(...) ...の最初の行で使用し、2番目の行で使用し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バイト

2つの等しい長さのソリューション:

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 nD n -1(⋯(D 3D 2 S 1 + S 2)+ S 3)))+ S n -1として書き直しました)+ S nFold両方のリストに関数を追加するだけです。


1

実際には、13バイト

;pX╗lr`╜tπ`M*

オンラインでお試しください!

このプログラムは、インデックスのリストを最初の入力として、次元のリストを2番目の入力として受け取ります。

説明:

;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)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.