配列の展開解除


34

この課題はMathematica.SEに関する質問に触発されました

任意の構造のネストされたリスト/配列があるとします(各レベルのリストは必ずしも同じ長さではありません)。簡単にするために、ノードは負でない整数または空の配列であると仮定します。例として

[[[1, 3], 2], [1, 4], 12, [[0, [], 0], [5, [7]]]]

リストをフラット化してノードの操作を実行する方が便利な場合があります。たとえば、

--> [1, 3, 2, 1, 4, 12, 0, 0, 5, 7]
--> [1, 1, 0, 1, 0, 0, 0, 0, 1, 1]

しかし、最終的には元の構造を保存したいので、これを元に戻したい

--> [[[1, 1], 0], [1, 0], 0, [[0, [], 0], [1, [1]]]

あなたの仕事は、その最後のステップを実行することです。

結果の目的の構造を表す任意の非負整数のネストされたリストと、目的の値を表す非負整数のフラットリストが与えられた場合、フラットリストを構造化リストの形式に変更します。両方のリストに同じ数の整数が含まれていると想定できます。

いつものように、無効な入力を処理する必要はありません(たとえば、2番目のリストがフラットではない、入力が構文的に不正である、ノードとして整数がないなど)。コード内の入力配列を変更できます。

STDIN、コマンドライン引数、または関数引数を介して入力を取り、関数またはプログラムを作成し、結果を返すか、STDOUTに出力できます。便利なリスト形式または文字列形式を使用して、入力と出力を表すことができます(形式が明確で、入力が前処理されていない限り)。また、両方の入力の形式は一貫している必要があります(たとえば、一方の入力を文字列として、もう一方の入力をリストとして使用することはできません)。入力リストはどちらの順序でも取得できますが、回答に正確な入力方法を指定してください。

もう1つの制限:正規表現を使用しないでください。これは配列操作の課題であり、文字列操作の課題ではありません。

これはコードゴルフなので、最短の回答(バイト単位)が勝ちです。

テストケース

Structure                             Values                 Result
[[[1,3],2],[1,4],12,[[0,0],[5,[7]]]]  [1,1,0,1,0,0,0,0,1,1]  [[[1,1],0],[1,0],0,[[0,0],[1,[1]]]]
[[[0,0],0],[0,0],0,[[0,0],[0,[0]]]]   [1,1,0,1,0,0,0,0,1,1]  [[[1,1],0],[1,0],0,[[0,0],[1,[1]]]]
[]                                    []                     []
[[]]                                  []                     [[]]
[0,1,2,3]                             [5,1,0,5]              [5,1,0,5]
[[[[[0]]]]]                           [123]                  [[[[[123]]]]]
[0,[1,[]],[[]],[2,3],[]]              [1,6,1,8]              [1,[6,[]],[[]],[1,8],[]]

Structure配列の値が変更された場合、許可されますか?
ProgramFOX

@ProgramFOXはい。「コード内の入力配列を変更できます。」
マーティンエンダー

皮肉なことに、ここでの提出物の1つはMathematicaにあります。
イサイアメドウズ

1
@impinball私が質問と一緒に投稿したのは、リンクされた質問から他の誰かが答えを盗むのを防ぐためです(実際、それは単にその答えのゴルフバージョンです)。
マーティンエンダー

@MartinBüttnerああ。いいね これも実際には短い答えの1つです。
イサイアメドウズ

回答:


9

CJam、18 16 13バイト

lA,sNerN%l~]z

前のCJamの回答と同じ形式でSTDINを介して入力を受け取ります。

[0 [11 []] [[]] [2 3] []]
[1 6 1 8] 

結果の文字列をSTDOUTに出力します

[1 [6 []] [[]] [1 8] []]

最初の行を文字列として扱い、すべての数字を改行に変換し、1つ以上の改行を分割して、2番目の行をスタックの配列として配置し、配列にラップして、2つの配列(行)を圧縮します。印刷は自動的に行われ、最初の行は文字列として扱われたため、括弧が保持されます。

コード拡張

lA,sNerN%l~]z
l                     "Read the first line of input. This is the nested array";
 A,s                  "Get array [0,1,2...9] and  convert it to string '012..9'";
    Ner               "Replace all occurrences of 0,1,2,..9 with new line";
       N%             "Split on one or more occurrences of new line";
         l~           "Read the second line as an array";
           ]          "Wrap both the splitted string and the second line array";
                      "in an array";
            z         "Transpose the array, there by placing the numbers from second";
                      "input array in the split holes of first input string";

3バイトを保存してくれた@ user23013に感謝します。

こちらからオンラインでお試しください


OPから、「これは文字列操作のチャレンジではなく、配列操作のチャレンジです。」
atk

@atk:OPは明示的に正規表現を禁止するだけなので、議論の余地があります。
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

1
略記/La-%
jimmy23013

@ user23013うわー、それ%が分割のためでもあることに気付くことは決してありませんし、それも複数のオカレンスに分割されます!
オプティマイザー

@atkはい、正規表現のみが禁止されているため、この手法を使用しました。
オプティマイザー

25

JavaScript、ES6、44バイト

f=(a,b,i=0)=>a.map(x=>x.map?f(x,b,i):b[i++])

これは、次のfように呼び出すことができる関数を作成します

f([0,[1,[]],[[]],[2,3],[]],[1,6,1,8])

すなわち、入力引数としてのネストされた配列と値の配列。関数の出力は、変換されたネストされた配列です。

この質問は再帰にとって非常に良い質問です。そのため、答えはきちんとした甘い関数です。メソッドfを使用して最初の引数を変換する関数を作成しますmap。各要素について、要素が配列のf場合、再度呼び出します。それ以外の場合、整数の場合、i 番目のアイテムを取得し、それを返し、値を増やしますi。の値はi、正しい順序を維持するために、各再帰呼び出しで渡されます。

mapメソッドを使用して、配列と整数の検出が再び行われます。配列変数の場合、map有効な関数ですが、整数変数の場合、map変数に対して定義されたプロパティや関数は呼び出されません。

これは、最新のFirefoxブラウザで動作します(ES6による)。


3
「+1」や「ありがとう」のようなコメントは避けるべきだと思いますが、これは1つの甘いES6関数です!私は何時間もこのコード行を見ることができます:)
ジェイコブ14

.mapはコードに2つが存在することを確認します。さらに短縮する方法はありますか?とにかく、素敵なコード!
デレク朕會功夫14

えー、ESはいつラムダ構文を追加しましたか?
ふわふわ14

ES6の@fluffy;)
オプティマイザー14

@Derek朕會功夫残念ながらいいえ。mapはコンテキストに結び付けられているため、最初のマップはに属しa、次のマップはx反復でそれぞれに属します。map配列を参照したり、整数と配列を区別したりする他の短い方法はありません
オプティマイザー14

18

JavaScript、ES6、41バイト

オプティマイザーの答えには本当に感銘を受けました。非常に巧妙に行われ、多くのことを学びました。しかし、それを見て、私はそれをわずかに短くして小さなバグを修正する方法を見つけました:

f=(a,b)=>a.map(x=>x.map?f(x,b):b.shift())

i変数を取り出して、に置き換えましたshift()。これにより、わずかに短くなりi、参照ではなく値で渡されるという問題を修正します。魔女は、最終的な配列からのいくつかの数字を繰り返し、最後のいくつかは使用されませんでした。繰り返しになりますが、オプティマイザーの答えは非常によく考えられていて、思っていたよりも優れていました。少し修正しました。


2
素敵なゴルフ!P:Aは、私はそれをキャッチしなかったことを悲しいビット
オプティマイザ

16

Dyalog APL、14文字

これは簡単です:(∊a)←b

通常、フラット化を∊a意味aしますが、割り当ての左側で発生する場合、この問題が求めていることを正確に実行します。関数であるという要件を満たすためには、いくつかの追加の波線が必要です:({a←⍺⋄(∊a)←⍵⋄a}ラムダの中括弧; そして左右の引数に、文の区切りのために)。

tryapl.orgでテストします。APLでは、空の数値ベクトルは( "zilde")で示されることに注意してください。1要素ベクトルは(,A)(A)、スカラーを意味するます。出力では、このこと:

┌⊖┐
│0│
└~┘

空の数値ベクトルを表します。0中心部には、アレイの要素ではない「プロトタイプ要素」を示します。


1
そのグラフィカルな表現は区別されませんか(,1)(1)または最後のビットが[1|1]代わりにとして提示されるのはなぜ[1|[1]]ですか?
マーティンエンダー14

tryaplが使用するグラフィカルな表現(として知られている]box on)は、それらを区別しません。Dyalog(displayfrom dfns.dws)には別の機能がありますが、残念ながらtryaplは追加のワークスペース(つまりライブラリ)の読み込みを制限します。:(
ngn 14

1
結果を角括弧形式で表示するには、次を試してください∊{0=⍴⍴⍵:⍕⍵ ⋄ '['(∇¨⍵)']'}a。またはこれ:∊{0=⍴⍴⍵:⍕⍵ ⋄ '['(1↓,'|',[1.5]∇¨⍵)']'}aセパレーターを主張する場合|
ngn 14

ああ、]display atryapl でも使用できます。構造に関する完全な情報を提供します。申し訳ありませんが、最初はこれに気付きませんでした。
ngn 14

公正なポイント。2バイト余分にコストをかけて関数に変換しました。
NGN

10

Python、51

f=lambda a,b:[b.pop(0)if x<[]else f(x,b)for x in a]

例:

>>> f([0,[1,[]],[[]],[2,3],[]], [1,6,1,8])
[1, [6, []], [[]], [1, 8], []]

10

Python 2、50

f=lambda s,v:v.pop(0)if s<[]else[f(x,v)for x in s]

これは非常に美しい問題でした。作業を続けるうちに、コードの一部が不要であることに気付き続け、ロジックが単純な式に崩壊しました。ゴルフのほとんどは、正しいアルゴリズムを見つけることでした。

sは構造でvあり、リストのフラットリストです。考え方はs、整数がであるかどうかをチェックすることですs<[](Python 2は、数値をリストよりも小さいものとして扱います)。ある場合は、の最初の要素を取得して返し、vから削除しvます。それ以外の場合は、のサブリストを再帰的に調べsます。

pop 非常に機能的なスタイルのコードで不可欠魔法の一部です。すべてvが同じインスタンスを指しているため、1つの要素からポップすると、v実行ツリー全体から要素が削除されるため、の各番号vは1回だけ使用されます。リストの理解[f(x,v)for x in s]は、深さ優先で左から右に展開される呼び出しツリーを作成し、要素をv正しい順序でスロットに入れます。

私はgrcの答えとは独立してこれを書きましたが、シングルを動かすまで同じことが判明しました[(および変数名)。この移動により、スペースのために文字が節約されます。ブラケットの移動とは、リスト内包表記の一部としてではなく、関数内でノードケースを即座に処理することを意味しますが、これは考慮していませんでした。

入力要件を拡張してSTDINから値を取得し、関数の引数として構造体を取得する場合、49の charを保存できます。これにより、を使用できますmap

v=input()
g=lambda s:v.pop(0)if s<[]else map(g,s)

9

ルビー、39

f=->a,b{a.map{|d|f[d,b]}rescue b.shift}

リスト内の要素が整数になるまで再帰します。
Integer.mapを呼び出すと例外
が発生するため、レスキュー部分に進み、2番目のリストから1番目の要素を「ポップ/シフト」します。

Regex soln ...もう少し長く:

f=->a,b{eval a.to_s.split(/\d+/).zip(b)*''}

いくつかのテストケースで試してみてください


参考のために、正規表現ソリューションは許可されていません。;)
マーティンエンダー


5

Haskell、113 104バイト(データ型宣言から86 + 18)

data N=I Int|L[N]
L[]!v=(L[],v)
L(a:b)!v|(c,w)<-a!v,(L d,u)<-L b!w=(L$c:d,u)
_!(n:m)=(I n,m)
s#v=fst$s!v

Haskellにはネストされた配列データ型が組み込まれていないため、独自のデータ型をロールバックする必要がありました。このため、プログラムにはパターンマッチングと明示的な構造再帰のみが含まれています。最後のテストケースは

L[I 0,L[I 1,L[]],L[L[]],L[I 2,I 3],L[]]#[1,6,1,8]

そして評価する

L[I 1,L[I 6,L[]],L[L[]],L[I 1,I 8],L[]]

4

Mathematica、41バイト

Function[,m[[i++]],Listable][i=1;m=#2;#]&

これは名前のない関数で、構造体を最初の引数として、値のリストを2番目の引数として取ります(そしてリストを返します)。

これは受け入れられた答えのゴルフ版ですこの課題に影響を与えた質問。私はこれを自分で投稿していますが、この答えを受け入れません(実際に最短のままであるはずです。これは、基本的に答えをコピーして、他の誰かがチャレンジに勝つことを防ぐためです。

使い方:

  • Listable純粋な関数を定義します。リスト可能な関数は、リスト自体ではなく、リスト引数の要素に(再帰的に)自動的に適用されるためf、構造化リストを呼び出すと、基本的に同じ整数のリストが返さif[i]ます。
  • 値リストをグローバルに保存しm、カウンターをに保存しますi
  • f(引数に関係なく)を呼び出すたびに、の次の要素を返しmます。

4

レボル-87 66 60

f: func[a[block!]b][map-each n a[any[attempt[f n b]take b]]]

ゴルフをしていない:

f: func [a [block!] b] [
    map-each n a [
        any [
            attempt [f n b]  
            take b
        ]
    ]
]

例:

>> f [0 [1 []] [[]] [2 3] []]   [1 6 1 8]           
== [1 [6 []] [[]] [1 8] []]

4

C#、225 + 13 = 239185 + 35 = 220172 + 35 = 207バイト

これが必要です:

using System;using o=System.Object;

object[]sを引数として受け入れます。

o[]u(o[]a,o[]b){var c=a;int i=0;Action<o[],o[]>d=null;d=(e, f)=>{for(int j=0;j<e.Length;j++){if(e[j]is int){f[j]=b[i];i++;}else{d((o[])e[j],(o[])f[j]);}}};d(a,c);return c;}

未ゴルフコード:

object[] Unflatten(object[] structure, object[] values)
{
    var c = structure;
    int i = 0;
    Action<object[], object[]> recursiveFunc = null;
    recursiveFunc = (e, f) =>
    {
        for (int j = 0; j < e.Length; j++)
        {
            if (e[j] is int)
            {
                f[j] = values[i]; i++;
            }
            else
            {
                recursiveFunc((object[])e[j], (object[])f[j]);
            }
        }
    };
    recursiveFunc(structure, c);
    return c;
}

2
を使用using o=System.Objectして、すべてのインスタンスobjectを単にに置き換えることで、もう少し短くすることができますomsdn.microsoft.com/en-us/library/sf0df423.aspx-Kroltan
1

1
@Kroltan素晴らしいヒント、ありがとう!
ProgramFOX

Clone浅いです。入力の変更が許可されている場合、クローンを作成する必要はまったくありません。許可されていない場合は、適切な複製が必要です。
CodesInChaos

@CodesInChaosなるほど。入力配列の変更が許可されているため、クローンを削除しました。ありがとう!
ProgramFOX

3

Python 2、64バイト

def g(N,L):f=lambda N:L.pop(0)if`N`<":"else map(f,N);return f(N)

リストのリストが好きだと聞いたので、関数に関数を入れました。

編集:grcの答えを見ると、それは完全に不要であることがわかりました。しかたがない...


3

SWI-プロローグ82

f([],A,[],A):-!.
f([H|T],A,[J|U],B):-(is_list(H),!,f(H,A,J,C);A=[J|C]),f(T,C,U,B).

サンプル実行:

?- f([[[1,3],2],[1,4],12,[[0,[],0],[5,[7]]]],[1,1,0,1,0,0,0,0,1,1],R,[]).
R = [[[1,1],0],[1,0],0,[[0,[],0],[1,[1]]]].

[]クエリの最後は、要素の数の不一致をチェックするためのもので、この質問では必要ないようです。


カット(および、ひいては高価なis_list)が必要な理由は何ですか?
無関係な文字列

1
@UnrelatedString:正しい答えを得るのに不要であるとわかった場合は、答えを直接編集してください。私のプロローグは当時は悪く(私はライブラリを使用して広範囲にカットしています)、最近ではさらにさびていました。
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

2

アーラン、116 93バイト

f(R,F)->put(n,F),[g(X)||X<-R].
g([H|T])->[g(H)|g(T)];g([])->[];g(E)->[H|T]=get(n),put(n,T),H.

2つの不純な関数fとを使用しgます。は、フラットリストにf設定nしてプロセスディクショナリを操作し、ネストされたリストの各要素をにマップしg(X)ます。g次にn、リスト以外の値が検出されるたびにフラットリストの末尾に設定し、フラットリストの先頭を返します。


1

Perl 5、49バイト

最初の引数はテンプレート構造で、2番目は値です。

sub u{($t,$l)=@_;ref$t?[map{u$_,$l}@$t]:shift@$l}

テストプログラム

use Test::More;
use Test::Deep;

sub u{($t,$l)=@_;ref$t?[map{u$_,$l}@$t]:shift@$l}

cmp_deeply u([[[1,3],2],[1,4],12,[[0,0],[5,[7]]]],[1,1,0,1,0,0,0,0,1,1]),[[[1,1],0],[1,0],0,[[0,0],[1,[1]]]];
cmp_deeply u([[[0,0],0],[0,0],0,[[0,0],[0,[0]]]],[1,1,0,1,0,0,0,0,1,1]),[[[1,1],0],[1,0],0,[[0,0],[1,[1]]]];
cmp_deeply u([], []), [];
cmp_deeply u([[]], []), [[]];
cmp_deeply u([0,1,2,3], [5,1,0,5]), [5,1,0,5];
cmp_deeply u([[[[[0]]]]], [123]), [[[[[123]]]]];
cmp_deeply u([0,[1,[]],[[]],[2,3],[]], [1,6,1,8]), [1,[6,[]],[[]],[1,8],[]];
done_testing;

1

Powershell:115

入力配列は$ i、マッピングは$ m、出力は$ o

$h={if($_.GetType().IsArray){if($_.c -eq 0){,@()}else{,@($_|%{.$h})}}else{$m[$c++]}};$i|%{$o=@();$c=0}{$o+=,(.$h)}

$ hは再帰関数を含む文字列であり、。$ h ...を使用して文字列に含まれるコードを実行できます。また、powershellが単一値配列をスカラーに平坦化することを要求しない場合、30バイト短くなります。単一のヌル値からヌルへ

結果を検証するための便利な配列構造ビューア

$j={if($_.GetType().IsArray){write-host '(' -n;($_|%{.$j});write-host ')' -n}else{write-host "$_" -n}};write-host '(' -n;$o|%{(.$j)}; write-host ')' -n;

編集:149

unflatten.ps1として保存します。

$m=[array]$args[1];$h={if($_.GetType().IsArray){if($_.c -eq 0){,@()}else{,@($_|%{.$h})}}else{$m[$c++]}};$args[0]|%{$o=@();$c=0}{$o+=,(.$h)};echo $o;

編集:136、インライン出力配列の作成と書き込み出力

$m=[array]$args[1];$h={if($_.GetType().IsArray){if($_.c -eq 0){,@()}else{,@($_|%{.$h})}}else{$m[$c++]}};echo(,@($args[0]|%{$c=0}{.$h}))

。\ unflatten.ps1 [入力配列] [マッピング配列]で呼び出します

出力はパイプラインに書き込まれるため、最初にこれを実行します。

Function View-Array{
Param([Parameter(ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)]
      [array]$o)

    PROCESS{
    $j={if($_.GetType().IsArray){write-host '(' -n;($_|%{.$j});write-host ')' -n}else{write-host "$_" -n}};
    write-host '(' -n;$o|%{(.$j)}; write-host ')' -n;
    }
}

で実行する

.\unflatten.ps1 [input array] [mapping array] | View-Array

1

C#、(40 + 123)= 163バイトまたは(67 + 81)= 148バイト

C#は、静的型付けと長い名前空間に苦しんでいます。

配列法

ステートメントの使用:

using o=System.Object;using System.Linq;

コード:

o[] u(o[] x,o[] y){int i=0;Func<o[],o[],o[]> f=null;f=(a,b)=>a.Select(e=>e is int?b[i++]:f((o[])e,b)).ToArray();return f(x,y);}

スタック方式(配列の代わりにStack構造を使用)

ステートメントの使用:

using s=System.Collections.Generic.Stack<object>;using System.Linq;

コード:

System.Func<s,s,s>f=null;f=(a,b)=>new s(a.Select(e=>e is int?b.Pop():f((s)e,b)));

ここで最初の試み、最初のコードゴルフ。

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