展平阵列!


34

在这个挑战中,您的任务是创建一个程序,该程序接受一个嵌套数组并返回一维扁平化数组。例如[10,20,[30,[40]],50]应该输出[10,20,30,40,50]


输入项

输入将是一个嵌套数组(例如[10,20,[[[10]]]])。它仅包含整数(负数和正数),字符串和数组。您可以将输入作为函数参数STDIN或任何适合您的语言的参数。您可以假设输入数组将没有空数组。


输出量

输出将是一个扁平的一维数组,具有与嵌套数组中相同类型的相同元素,并且顺序相同。


测试用例

[10,20,30] -> [10,20,30]
[[10]] -> [10]
[["Hi"],[[10]]] -> ["Hi",10]
[[[20],["Hi"],"Hi",20]] -> [20,"Hi","Hi",20]
[[["[]"],"[]"]] -> ["[]","[]"]


随时要求使用注释进行任何澄清。这是,因此以字节为单位的最短代码胜出!

注意: 如果您的语言中包含内置语言,则不得使用它。


编辑

另请提供指向可以执行您的代码的网站的链接。


7
有些语言将字符串视为数组,[[“ Hi”],[[10]]]-> [“ H”,“ i”,10]可以吗?
阿达姆,2013年

4
@Mego我也很惊讶地发现PPCG上有一个unflatten问题,但没有任何flatten问题。
Arjun

3
如果您的语言仅支持相同大小的子数组怎么办?(例如Java?)如果每个元素的类型必须相同怎么办?(例如Java,C ++等?)此外,请添加例如["[",[["[",],'[',"['['"]]作为测试用例。
瑕疵的

4
@flawr该测试用例仅对支持bot '"定界符的语言有意义。(但是,我认为,一个测试用例包括[]"\在字符串中是有用的。)
马丁安德

4
测试用例还排除了不支持多种类型的数组或其他类型的数组文字的语言。
瑕疵的

Answers:


40

K,3个字节

,//

这是一个相当普遍的习惯用法。“加入融合”。

可以在这里尝试

怎么运行的:

Join(,)将原子或列表融合在一起以生成列表。结束于/)接受动词(在这种情况下为join),并将其从左到右应用于列表的每个元素之间。因此,该化合物,/将使列表的所有顶级元素变平。该符号/实际上具有不同的含义,具体取决于与其混合的动词的价态(参量)。当我们提供,/动词时,最终词/充当“收敛”-它反复应用于,/输入,直到停止更改。其他一些语言将这种功能称为“定点组合器”。通过重复融合底层列表,您最终将到达一个平面列表,并且所有操作都不会干扰元素的顺序。这似乎解决了问题。


1
好的,谢谢您的解释!让您的来之不易的+1。
价值墨水


1
我想出了相同的算法(但不是这种语言)。+1选择适合的语言以实现它!
Cyoce

@Cyoce如果您的语言与此处使用的三个运算符等效,那么这是一个非常自然的解决方案。一定要发布您的变化。
JohnE

1
@JohnE长话来说,我是从我想出的算法中衍生出一种语言,因此该语言尚未完成(并因此得以实现)。
Cyoce

38

JavaScript(ES6),35个字节

受到@ user81655的回答的启发:

f=a=>a.map?[].concat(...a.map(f)):a

3
非常聪明!对于[ab]使用JS的奇怪方法来处理丢失的密钥,可以+1!
Cyoce

我可以击败。
秃头Bantha

@BaldBantha:我们期待您的回答:-)
Bergi,2016年

2
废话NVM我的33字节解决方案在其中一种测试用例上失败。NOOOO
秃头Bantha

2
@ BaldBantha,join-split将在字符串内的逗号上失败。
Qwertiy

19

Mathematica,16个 14字节

{##&@@#&//@#}&

一个未命名的函数,它接收并返回一个列表,例如:

{##&@@#&//@#}& @ {{{20}, {"Hi"}, "Hi", 20}}
(* {20, "Hi", "Hi", 20} *)

说明

语法糖方!

为了理解这个作品,注意在数学每个表达式或者是一个原子(例如数字,字符串,符号)或以下形式的化合物的表达如何f[a, b, c, ...],其中fabc本身是任意表达式。在这里,f称为表达式的。最重要的是语法糖。例如{a, b, c},只是List[a, b, c]

我们从//@将功能映射到列表的所有级别开始。例如:

f //@ {{{20}, {"Hi"}, "Hi", 20}}
(* f[{f[{f[{f[20]}], f[{f["Hi"]}], f["Hi"], f[20]}]}] *)

请注意,此地图 f了原子以及化合物表达式。我们现在正在寻找的是摆脱列表头并保留所有其他内容的方法。

Apply函数通常用于将列表的元素作为单独的参数提供给函数,但是其实际定义更为笼统,并且仅替换表达式的头部。例如Apply[g, f[a, b]]g[a, b]

现在有一个特殊的“头” Sequence,它消失了。例如{a, Sequence[b, c], d},计算结果为{a, b, c, d}。扁平化列表的想法是将所有内部列表的头替换为,以Sequence使它们被溅入周围的列表中。因此,我们想要的是Apply头部Sequence到列表中。如果我们方便Apply对某个原子进行处理,它只会使该原子保持不变,因此我们根本不必区分表达式的类型。

最后,有一个小问题:f也应用于最外层,因此它也删除了List我们不想要的最外层。最简单的应对方法是将结果再次包装在列表中,以便周围环境Sequence可以安全消失。

请注意,代码中既没有Apply也不存在Sequence@@是的操作形式Apply##&是一个标准的高尔夫球技巧,以缩短久内置名Sequence。因此,将所有内容解囊化,我们得到的是:

flatten[list_] := { MapAll[Apply[Sequence], list] }

有关如何工作以及为什么##&工作的更多详细信息,请参阅我对Mathematica技巧的回答中的 “参数序列”部分。


第一次见过//@。了解非常有用!
DavidC

//@捕捉整齐的图案。让我想起了Joy中的一些递归组合器。您是否有指向Mathematica中任何相关函数的良好参考的链接?我对将显式递归从程序中分解出来的方式非常感兴趣。
JohnE '16

1
@JohnE好,这是docs。您还可以看看之类的东西MapMapAtApply,以及Replace和相关功能。通常,尽管有很多函数带有可选的levelspec参数(请参阅我最初的16字节解决方案),该参数使您可以一次在多个/所有级别上应用该函数。
Martin Ender

12

Python 2,43个字节

f=lambda l:[l]*(l*0!=[])or sum(map(f,l),[])

在列表上,递归于元素并连接结果。在字符串或数字上,包含在单例列表中。

不幸的是,Python 2对类型的排序int < list < stringlist在其他类型之间,需要检查两个不等式。因此,将l*0对照空列表进行检查[],否则给出0""


10

Ruby,43 42 34字节

递归解决方案。现在有了异常处理!(尽管值得赞扬@akostadinov,但它启发了这一变化)

f=->a{a.map(&f).inject:+rescue[a]}

IDEOne链接


短促,超赞
akostadinov

我不知道,你可以使用rescue这样的
Cyoce

1
@Cyoce我认为这是因为Ruby从技术上讲没有try块,因此您可以使用begin来区分要捕获的部分和不需要的部分。因此,既然您正在捕获整个块之前的所有内容,那么从技术上讲您不需要它吗?剩下的只是修剪空白,因为Ruby将该行解释为...inject(:+) rescue [a]
Value Ink

1
@ KevinLau-notKenny,不,同一行的救援有所不同,只是抢救该行。例如a = raise("haha") rescue 1将分配1a。它”
akostadinov

@ KevinLau-notKenny有一个内联rescue,就像有一个内联ifwhile
基金莫妮卡的诉讼

8

JavaScript(ES6),41个字节

f=a=>[].concat(...a.map(v=>v.pop?f(v):v))
<textarea id="input" rows="6" cols="40">[[[20],["Hi"],"Hi",20]]</textarea><br /><button onclick="result.textContent=JSON.stringify(f(eval(input.value)))">Go</button><pre id="result"></pre>


8

Perl 6,24个字节

{gather {$_».&{.take}}}

说明:

{ # has $_ as an implicit parameter

  gather {

    $_\ # the parameter from the outer block
    »\  # for each single value in the structure
    .&( # call the following block as if it was a method
      { # this block has its own $_ for a parameter
        .take # call the .take method implicitly on $_
      }
    )
  }
}

测试:

#! /usr/bin/env perl6

use v6.c;
use Test;

my &flatten = {gather {$_».&{.take}}}

my @tests = (
  [10,20,30], [10,20,30],
  [[10,],], [10,],
  [["Hi",],[[10,],],], ["Hi",10],
  [[["[]",],"[]"],], ["[]","[]"],
);

plan @tests / 2;

for @tests -> $input, $expected {
  # is-deeply cares about the exact type of its inputs
  # so we have to coerce the Seq into an Array
  is-deeply flatten($input).Array, $expected, $input.perl;
}
1..4
ok 1 - $[10, 20, 30]
ok 2 - $[[10],]
ok 3 - $[["Hi"], [[10],]]
ok 4 - $[[["[]"], "[]"],]

7

Haskell,43个字节

data D a=L a|N[D a]
f(L x)=[x]
f(N l)=f=<<l

Haskell既没有具有不同深度的子列表的嵌套列表,也没有列表元素的混合类型。对于嵌套,我定义了一个自定义数据类型D,该数据类型可以是L包含某些元素的叶子,也N可以是包含Ds 的列表的节点。对于混合元素,我使用预定义的数据类型Either,该数据类型将两种类型合并为一种Either String Integer。新类型D和flatten函数f在叶子元素的类型中是完全多态的,因此,我无需特别注意Either

用法示例:f (N[N[L(Right 20)], N[L(Left "Hi")], L(Left "Hi") , L(Right 20)])-> [Right 20,Left "Hi",Left "Hi",Right 20]


6

Pyth,7 6 5字节

us+]Y

在线尝试:演示测试套件

但是当然,还有一个内置函数,可以仅用2个字节来处理任务:.nTest Suite


距离目前的获胜者仅3个!+1
Arjun

@Sting:打掉另一个字节。G如果我不写的话,Pyth会隐式附加最后一个字符。
雅库布

恭喜你!
Arjun

6

JavaScript(Firefox 30-57),43个字节

f=a=>a.map?[for(b of a)for(c of f(b))c]:[a]

仅仅因为我什至可以避免使用concat


是不是它的EcmaScript 6不是火狐30+
所罗门·乌科

1
@SolomonUcko不,[for(of)]仅在Firefox 30+中可用。它是为ES7提出的,但后来放弃了。
尼尔

1
感谢您的解释!大多数时候,我只是认为这是for(__ in __)
所罗门会员名:Ucko

@SolomonUcko [for(in)]是另一种实验性语法,为您提供了对象的键。
尼尔

5

Perl,34个 29字节

功能。

如果需要扁平化列出,如my @a = f(@a)29个字节:

sub f{map{ref()?f(@$_):$_}@_}

在Ideone上测试

如果需要展平到数组ref,如my $a = f($a)34个字节:

sub f{[map{ref()?@{f(@$_)}:$_}@_]}

在Ideone上进行测试

Perl 5.22.0 +,27个字节

多亏霍布斯

如果需要扁平化列出,例如my @a = f(@a)27个字节:

sub f{map{ref?f(@$_):$_}@_}

在JDoodle上测试

如果需要展平到数组ref,如my $a = f($a)32个字节:

sub f{[map{ref?@{f(@$_)}:$_}@_]}

在JDoodle上测试


我还没有测试过,但是认为?@{f@$_}:应该可以工作,而不是?@{f(@$_)}:节省两个字节。
msh210 '16

1
@ msh210不,它不起作用。编译器不知道这f是一个函数,因为f尚未声明。sub f{}sub f{... f@$_ ...}工作。
丹尼斯·伊巴耶夫

1. ref不需要parens工作,节省2个字节。2.据我所知,sub f{map{ref?f(@$_):$_}@_}在规则之内并保存另一个。5. f将一个数组(nonref)作为列表,因此它可以返回相同的数组。
霍布斯(Hobbs)

@hobbs 1.如果不加括号,ref则编译器会假定?正在?PATTERN?像那样开始操作ref(?PATTERN?)。因此,编译器将进行第二次搜索?并引发错误。
丹尼斯·伊巴耶夫

@DenisIbaev啊。?PATTERN?已在5.22.0中删除(m?PATTERN?仍然有效),并且我正在测试最新版本。因此,您可以通过指定5.22+获得这两个字节。
霍布斯(Hobbs)

4

朱莉娅,29个字节

f(x,y=vcat(x...))=x==y?x:f(y)

这是递归地喷射到连接函数中,直到到达固定点为止。例

julia> f([1,[2,[3,[4,[5,[6]]]]]])
6-element Array{Int64,1}:
 1
 2
 3
 4
 5
 6

3

视网膜,30字节

1>`("(\\.|[^"])+")|[][]
$1
$
]

在线尝试!(第一行仅用于一次运行多个测试用例。)

视网膜有没有数组,字符串文字或数字的概念,所以我决定去与一个“普通”的输入格式[...,...]风格数组和"-delimited串,在那里\可以将字符串中使用转义的任何字符(尤其是"\本身)。

程序本身仅匹配完整的字符串或方括号,然后替换为$1保留字符串并删除方括号的字符串。该限制会1>跳过第一个比赛,因此我们不会删除前导[。但是,这确实删除了结尾],因此我们在一个单独的阶段中将其重新添加。


3

Pyke,11个字节

.F~]+=])K~]

在这里尝试!

说明:

.F~]+=])    - Deep for loop
  ~]        -    contents of `]` ([] by default)
    +       -  ^+i
     =]     - `]` = ^
        K~] - Output value
        K   - Remove the output from the for loop
         ~] - Return the contents of `]`

或错误修正后的7个位元组

M?+]K~]

在这里尝试!

说明:

M?+]    - Deep map
 ?+]    -  `]` = `]`+i
    K~] - Output value
    K   - Remove the output from the for loop
     ~] - Return the contents of `]`

如果允许打印到标准输出,则甚至是2个字节(这可能是内置的)

M
<newline required>

在这里尝试!

这将print_newline功能深深地应用到输入中的每个非序列项,并递归序列项。


距K仅4!+1
Arjun

3

的Java(V8)390个 276字节

public static Object[] f(final Object[]a) {
    List<Object>r=new ArrayList<>();boolean t=false;int n=0;
    for(final Object p:a)
        if(t=p instanceof Object[]){for(final Object q:(Object[])p) r.add(q);}
        else r.add(p);
    return(t)?f(r.toArray()):r.toArray();
}  

仅出于完整性和所有目的。:)不能说Java的代码效率高。


3
您好,欢迎来到PPCG!这个问题是code-golf,所以请尽量减少您的代码。谢谢!
NoOneIsHere

3
删除所有不必要的空格,制表符和换行符。更改oafo,然后更改flattenf
NoOneIsHere

2
您不需要finals,整个事情可以是lambda,您不需要public static...
David Conrad

1
如果使用泛型而不是对象,则可以保存几个字符
user902383 '16

1
如果用替换false,还可以节省2个字节1>2,如果声明n但未定义(编译器会自动将其定义为0),则可能会另外获得2个字节
user902383 2016年

2

Python,57个字节

f=lambda a:sum([list==type(x)and f(x)or[x]for x in a],[])

在线尝试:Python 2Python 3

感谢Kevin Lau的for list==type(x)俩。


2
type(x)==list比短isinstance(x,list)
价值墨水

1
“它将只包含整数(负数和正数),字符串和数组。”那又怎么样[`x`>'['and...呢?(仅适用于Python2。)
Lynn

2

红宝石

有内置flatten方法。

您可以在此处运行:http : //www.tutorialspoint.com/execute_ruby_online.php

一个43字节,但可以共享:

f=->a{a.inject([]){|r,e|r+(f[e]rescue[e])}}

一个45个字节比前一个和另一个ruby回答更有效:

f=->a{a.map{|e|Array===e ?f[e]:[e]}.inject:+}

这是基准:

require 'benchmark'
n=10^9
arr=[[[20],[[[[[[[[123]]]]]]]],"ads",[[[[[[[4]]]]]]],5,[[[[[[[[[[6]]]]]]]]]],7,8,[[[[[[[[[[9]]]]]]]]]],[[[[[[[[[[0]]]]]]]]]],[[[[[[[[[[[["Hi"]]]]]]]]]]]],[[[[[["Hi"]]]]]],[[[[[20]]]]]]]
Benchmark.bm do |x|
  x.report { f=->a{a.map(&f).inject:+rescue[a]}; f[arr] }
  x.report { f=->a{a.map{|e|e!=[*e]?[e]:f[e]}.inject:+}; f[arr] }
  x.report { f=->a{a.inject([]){|r,e|r+(f[e]rescue[e])}}; f[arr] }
  x.report { f=->a{a.map{|e|Array===e ?f[e]:[e]}.inject:+}; f[arr] }
end

结果:

       user     system      total        real
   0.010000   0.000000   0.010000 (  0.000432)
   0.000000   0.000000   0.000000 (  0.000303)
   0.000000   0.000000   0.000000 (  0.000486)
   0.000000   0.000000   0.000000 (  0.000228)

1
您好,欢迎来到PPCG!不幸的是,由于以下规则,您的答案无效Note: If your language contains a built-in for this, then you must NOT use it
NoOneIsHere

@NoOneIsHere,谢谢,不知道这一点
akostadinov

1
我的新更新如何与您的时间相对堆叠?另外,就像我的新答案一样,您可以删除周围的空格rescue
Value Ink

@ KevinLau-notKenny更新,谢谢!rescue顺便说一句,看起来好像很慢,就像try/catch在Java中一样
akostadinov

1
也更新您的字节数
值墨


2

Clojure,68个字节

(def f #(if(some vector? %)(f(mapcat(fn[z](if(vector? z)z[z]))%))%))

mapcat首先将函数应用于每个元素,然后合并结果。因此,每当出现这种情况时,都会失去一个“嵌套级别”。Concat不适用于非序列,因此如果元素不是向量,则必须将其包装到向量中。

您可以在这里尝试:http : //www.tryclj.com

(f [[[20],["Hi"],"Hi",20]])
(f [[["[]"],"[]"]])

不错的第一个代码高尔夫球。+1 :)
Arjun

2

ANSI C,193个字节

#define b break;
#define c case
#define p putch(_);
char f;main(_){switch(_){c 1:putch(91);b c 34:f^=1;p b c 91:f&&p b c 93:f&&p b c 10:c 13:putch(93);return;default:p}_=getch();main(_);}

:-/, 有什么建议么?顺便说一句,我确实尝试找到了一个在线源来进行编译,但是WL对于编译此代码非常严格。否则它将适用于VS和gcc。


2
Welcome to PPCG!
Martin Ender

1
Welcome to PPCG! Nice first golf. Good luck ahead!
Arjun

Thanks! It was an attempt to up my points so that I can get commenting privileges elsewhere. It appears things don't work like that the accounts are for different portals. :D I will see if some nifty features from c++ can be used.
amritanshu

2

JavaScript 20 bytes

a=>(a+[]).split(',')

The array + array is equal to array.toString


@WheatWizard thanks for the welcome and I am new to the site. actually a is an argument of the function. I will try to edit out the function now.
i--

I think now it's ok @WheatWizard. Please let me know if there is a problem with this
i--

1
Actually looking at the javaScript docs an anonymous function would definitely be shorter, you would only have to add a=> to the beginning of your code.
Wheat Wizard

@WheatWizard I updated with the arrow function as you mentioned. But I have to remove the snippet because arrow function doesn't support direct invoke. It is only for callbacks
i--

1
This doesn't handle strings with commas in them correctly
Jo King

2

C#, 48 bytes

()=>{$"[{i.Replace("[","").Replace("]","")}]";};

Thought I'd post it also since nobody has given a C# solution yet. Suggestions welcome!


Welcome to the site. I haven't programmed in C# in a while but it looks to me that you might have a couple of issues. For one how is i initialized? and are you sure it works on the [["[]"],"[]"] example?
Wheat Wizard

Sorry, i is the input passed in as a string. An empty array would just translate to an empty string.
PmanAce

How about the last testcase? Also, I presume you meant to do i=>$"{i.Replace("[","").Replace("]","")}"?
Embodiment of Ignorance

Sadly doesn't work in the last case, it will get rid of empty array. :(
PmanAce

This answer doesn't pass the final test case. Since it has not been fixed for a few months, I'm voting to delete it.
mbomb007

1

Racket, 63 bytes

(define(f l)(apply append(map(λ(x)(if(list? x)(f x)`(,x)))l)))

1

Java 8 165 chars

import java.util.*;<T>T[]f(T[]a){List<T>l=new ArrayList<>();for(T e:a)if(e instanceof Object[])Collections.addAll(l,f((T[])e));else l.add(e);return(T[])l.toArray();}

Ungolfed into a class:

public class Q80096 {

    public static <T> T[] flatten(T[] array) {
        List<T> flattenedList = new ArrayList<>();
        for (T element : array)
            if (element instanceof Object[])
                 Collections.addAll(flattenedList, flatten((T[]) element));
            else
                flattenedList.add(element);
        return (T[]) flattenedList.toArray();
    }
}

This answer is based on Jeremy Harton's approach. I used it changed it in some places and created a more golf-like version.


would it be not better when using Arrays.asList() on "array" and then go the foreach with lambda and end this with a Collector?
Serverfrog

1

JavaScript, 17 Bytes

a=>eval(`[${a}]`)

Finally, JavaScript's type conversions can be put to some good use! Please note that this will actually output an array, but string conversion (putting it into HTML) causes it to become a comma separated list.

If comma separated lists are acceptable output, then the following is valid:

7 Bytes

a=>""+a

NOTE: Snippet is broken for some reason

var subject = 
  a=>eval(`[${a}]`)
<input oninput="try {output.innerHTML = subject(this.value)} catch(e) {output.innerHTML='Invaild Input'}" />
<div id="output"></div>


3
This doesn't seem to work when run in the console for input ["["]... I tried running (a=>eval([${a}]))(["["]) and got a SyntaxError
jrich

@jrich. You just get this error when you type character by character. If you copy and paste any valid array, it will work as expected. By the way, nice answer SpeedNinja, I would only change oninput event with a button click.
Washington Guedes

This doesn't work for strings with commas in them
Jo King


1

Attache, 14 bytes

{Reap[Sow@>_]}

Try it online!

Fortunately, Attache has a "vectorization" operator, which applies a function at the atoms of a list. In this case, all we need to do is to set up a reaper with Reap and Sow all atoms of the input _ with @>. I think it's quite elegant.

Alternatives

15 bytes: Fixpoint{`'^^_}

16 bytes: Fixpoint!&Concat

17 bytes: {q:=[]q&Push@>_q}

17 bytes: Fixpoint[&Concat]


1

Elixir, 74 bytes

def d(l)do l|>Stream.flat_map(fn x->if is_list(x)do d(x)else[x]end end)end

First Elixir answer, so can probably be golfed a bit.

Try it online.

Explanation:

def d(l)do l|>            # Recursive method taking a list as input:
  Stream.flat_map(fn x->  #  Map over each item `x` of the input-list:
    if is_list(x)do       #   If `x` is a list itself:
      d(x)                #    Do a recursive call with `x`
    else                  #   Else:
      [x]                 #    Simply leave `x` unchanged
    end                   #   End of the if-else statements
  end)                    #  End of the map
end                       # End of the recursive method

Of course, if builtins were allowed, this could have been 25 bytes instead:

fn(l)->List.flatten(l)end

Try it online.



By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.