Mathematica, 16 14 bytes
{##&@@#&//@#}&
An unnamed function which takes and returns a list, e.g.:
{##&@@#&//@#}& @ {{{20}, {"Hi"}, "Hi", 20}}
(* {20, "Hi", "Hi", 20} *)
Explanation
Syntactic sugar party!
To understand how this works, note that every expression in Mathematica is either an atom (e.g. numbers, strings, symbols) or a compound expression of the form f[a, b, c, ...], where f, a, b, c are themselves arbitrary expressions. Here, f is called the head of the expression. Everything else on top of that is just syntactic sugar. E.g. {a, b, c} is just List[a, b, c].
We start with //@ which maps a functions over all levels of a list. For instance:
f //@ {{{20}, {"Hi"}, "Hi", 20}}
(* f[{f[{f[{f[20]}], f[{f["Hi"]}], f["Hi"], f[20]}]}] *)
Note that this maps f over atoms as well as compound expressions. What we're now looking for is a way to get rid of the list heads and keep everything else.
The Apply function is normally used to feed the elements of a list as separate arguments to a function, but its actual definition is more general and simply replaces the head of an expression. E.g. Apply[g, f[a, b]] gives g[a, b].
Now there's a special "head" called Sequence that simply vanishes. E.g. {a, Sequence[b, c], d} just evaluates to {a, b, c, d}. The idea for flattening the list is to replace the heads of all inner lists with Sequence so that they get splatted into their surrounding list. So what we want is to Apply the head Sequence to the lists. Conveniently if we Apply something to an atom, it just leaves the atom unchanged, so we don't have to distinguish between types of expressions at all.
Finally, there's one small issue: f is also applied to the outermost level, so that it also removes the outermost List, which we don't want. The shortest way to counter that is simply to wrap the result in a list again, such that the surrounding Sequence can safely vanish.
Note that there's neither Apply nor Sequence in the code. @@ is an operator form of Apply and ##& is a standard golfing trick to shorten the long built-in name Sequence. So ungolfing everything a bit, we get something like:
flatten[list_] := { MapAll[Apply[Sequence], list] }
For more details on how and why the ##& works, see the section on "Sequences of arguments" in my answer for the Mathematica tips.
7Some languages treat strings as arrays, is [["Hi"],[[10]]] -> ["H","i",10] ok? – Adám – 9 years ago
@NᴮᶻNo, I'm afraid that isn't OK. – Arjun – 9 years ago
1I'm really surprised this isn't a duplicate – Mego – 9 years ago
4@Mego I was surprised too to find out that there was an
unflattenquestion but noflattenquestion on PPCG. – Arjun – 9 years agoIs it okay if the output is an array of all strings, but still contain the same values in the same order as the input array? For instance, is it okay if the input
[[[20],["Hi"],"Hi",20]]results in the output['20', "'Hi'", "'Hi'", '20']? – R. Kap – 9 years ago3What if your language only supports subarrays of the same size? (E.g. Java?) What if the type of each element must be the same? (E.g. Java, C++ etc.?) Also, please add e.g.
["[",[["[",],'[',"['['"]]as a test case. – flawr – 9 years ago4@flawr That test case only makes sense for languages that support bot
'and"as delimiters. (But I agree that a test case involving[,],"and\inside a string would be useful.) – Martin Ender – 9 years ago4The test cases also exclude languages which do not support these kinds of arrays with multiple types, or with another notation for array literals. – flawr – 9 years ago
@R.Kap Sorry but that's not allowed. I've edited the question also. – Arjun – 9 years ago
3@flawr Of course, but I think we always assume that you just rewrite the test cases with your language's syntax. Making using of something like redundant literal syntax that is only present in some languages seems unnecessarily specific. – Martin Ender – 9 years ago
2@flawr Java can have subarrays of different sizes (but not different types, thus not different 'depths'). – David Conrad – 9 years ago
3@DavidConrad not true - an array is an
Object, so anObject[]can contain other arbitraryObject[]. Obviously this isn't typesafe, and any algorithm flattening anObject[]would need to use reflection to work out what's going on. – Boris the Spider – 9 years ago2In C or asm (where polymorphic data types have to be implemented manually), I'm imagining accepting the multi-dimensional array in serialized form. i.e. treat the problem as a text-processing problem, just removing the internal unquoted
[and]characters :P – Peter Cordes – 9 years ago2If your chosen language can't handle nested arrays, why are you worrying about using it for this challenge? It obviously can't do this challenge, which is fine. On a side note, using
Object[]in Java andstd::any[]in C++17 (or the equivalentboost::anyin earlier C++ versions) would work. – Mego – 9 years ago1What if the language automatically flattens the input? – caird coinheringaahing – 9 years ago
3Requiring support for both numbers and strings just makes this challenge unnecessarily complicated, and deviates from the core task. – Erik the Outgolfer – 8 years ago
A test case like
["1",[2]]would probably be good. – Giuseppe – 8 years ago