Flatten a list: Difference between revisions

From Rosetta Code
Content added Content deleted
Line 613: Line 613:
While this is a common homework problem in Common Lisp, it should be noted that it is typically a mistake to use it in a realistic program; it is almost always easier to rewrite the program such that it does not generate the deeply-nested lists in the first place. In particular, note that flattening means that none of the values stored in the nested-list-structure can ''be'' a list (a cons or nil) itself. For example, producing and flattening a tree of boolean values would not do the right thing, since false = nil, a list.
While this is a common homework problem in Common Lisp, it should be noted that it is typically a mistake to use it in a realistic program; it is almost always easier to rewrite the program such that it does not generate the deeply-nested lists in the first place. In particular, note that flattening means that none of the values stored in the nested-list-structure can ''be'' a list (a cons or nil) itself. For example, producing and flattening a tree of boolean values would not do the right thing, since false = nil, a list.
=={{header|D}}==
=={{header|D}}==
There are many ways to implement this in D. This version minimizes heap activity using a tagged union. A similar object-oriented version too is possible. D v.2.
There are many ways to implement this in D. This version minimizes heap activity using a tagged union. A similar object-oriented version too is possible.

<lang d>import std.stdio: writeln;
The example has been modified so it {{works with|D|2}} the same way as it {{works with|D|1}} using {{libheader|tango}}
import std.conv: to;
<lang d>version(Tango) {
import tango.io.Stdout;
import tango.io.device.Array;
import tango.io.stream.Format;

} else {
import std.stdio : writeln;
import std.conv : to;
}


struct TreeList(T) {
struct TreeList(T) {
alias TreeList!(T) MyT;
bool isArr = true; // contains an arr on default
bool isArr = true; // contains an arr on default
union {
union {
TreeList!T[] arr;
MyT[] arr;
T data;
T data;
}
}


static TreeList!T opCall(Types...)(Types items) {
static MyT opCall(Types...)(Types items) {
TreeList!T result;
MyT result;


foreach (i, el; items)
foreach (i, el; items)
static if (is(Types[i] == T)) {
static if (is(Types[i] == T)) {
TreeList!T item;
MyT item;
item.isArr = false;
item.isArr = false;
item.data = el;
item.data = el;
Line 635: Line 645:
} else
} else
result.arr ~= el;
result.arr ~= el;

return result;
return result;
}
}

// this is better as a general free function
// this is better as a general free function
TreeList!T flatten() {
MyT flatten() {
TreeList!T result;
MyT result;

if (this.isArr)
if (this.isArr) {
foreach (el; this.arr)
foreach (el; this.arr)
result.arr ~= el.flatten().arr;
result.arr ~= el.flatten().arr;
else
} else {
result.arr ~= this;
version (D_Version2) {
result.arr ~= this;

} else {
result.arr ~= *this;
}
}
return result;
return result;
}
}

string toString() {
version(Tango) {
if (isArr)
char[] toString() {
return to!string(arr, "[", ", ", "]");
auto bf = new Array(1024);
auto f = new FormatOutput!(char) (bf);
else
return to!string(data);
if (isArr) {
f(arr);
} else {
f(data);
}
return cast(char[])bf.slice;
}
}
version (D_Version2) {
string toString() {
if (isArr) return to!(string)(arr, "[", ", ", "]");
else return to!(string)(data);
}
}
}
}
}

void main() {
void main() {
alias TreeList!(int) L; // 12 bytes if T is int
alias TreeList!(int) L; // 12 bytes if T is int
auto list = L(L(1), 2, L(L(3,4), 5), L(L(L())), L(L(L(6))), 7, 8, L());
auto list = L(L(1), 2, L(L(3,4), 5), L(L(L())), L(L(L(6))), 7, 8, L());
writeln(list);
version (Tango) {
writeln(list.flatten());
Stdout (list).newline;
Stdout (list.flatten()).newline;
} else {
writeln(list);
writeln(list.flatten());
}
}</lang>
}</lang>
Output:
Output:

Revision as of 18:33, 28 August 2010

Task
Flatten a list
You are encouraged to solve this task according to the task description, using any language you may know.

Write a function to flatten the nesting in an arbitrary list of values. Your program should work on the equivalent of this list:

  [[1], 2, [[3,4], 5], [[[]]], [[[6]]], 7, 8, []]

Where the correct result would be the list:

   [1, 2, 3, 4, 5, 6, 7, 8]

C.f. Tree traversal

ActionScript

<lang ActionScript>function flatten(input:Array):Array { var output:Array = new Array(); for (var i:uint = 0; i < input.length; i++) {

               //typeof returns "object" when applied to arrays. This line recursively evaluates nested arrays,
               // although it may break if the array contains objects that are not arrays.

if (typeof input[i]=="object") { output=output.concat(flatten(input[i])); } else { output.push(input[i]); } } return output; } </lang>

Aikido

<lang aikido> function flatten (list, result) {

   foreach item list {
       if (typeof(item) == "vector") {
           flatten (item, result)
       } else {
           result.append (item)
       }
   }

}

var l = [[1], 2, [[3,4], 5], [[[]]], [[[6]]], 7, 8, []] var newl = [] flatten (l, newl)

// print out the nicely formatted result list print ('[') var comma = "" foreach item newl {

   print (comma + item)
   comma = ", "

} println("]")

</lang> Output:

[1, 2, 3, 4, 5, 6, 7, 8]

ALGOL 68

Works with: ALGOL 68 version Revision 1 - no extensions to language used
Works with: ALGOL 68G version Any - tested with release 1.18.0-9h.tiny
Works with: ELLA ALGOL 68 version Any (with appropriate job cards) - tested with release 1.8-8d

Flattening is built in to all of Algol68's transput routines. The following example also uses widening, where scalars are converted into arrays.

<lang algol68>main:(

 [][][]INT list = ((1), 2, ((3,4), 5), ((())), (((6))), 7, 8, ());
 print((list, new line))

)</lang> Output:

         +1         +2         +3         +4         +5         +6         +7         +8

AutoHotkey

Works with: AutoHotkey_L

AutoHotkey doesn't have built in list data type. This examples simulates a list in a tree type object and flattens that tree. <lang AutoHotkey>list := object(1, object(1, 1), 2, 2, 3, object(1, object(1, 3, 2, 4) , 2, 5), 4, object(1, object(1, object(1, object()))), 5 , object(1, object(1, 6)), 6, 7, 7, 8, 9, object()) msgbox % objPrint(list) ; (( 1 ) 2 (( 3 4 ) 5 )(((())))(( 6 )) 7 8 ()) msgbox % objPrint(objFlatten(list)) ; ( 1 2 3 4 5 6 7 8 ) return

!r::reload !q::exitapp

objPrint(ast, reserved=0) {

 if !isobject(ast)
   return " " ast " "
 
 if !reserved
   reserved := object("seen" . &ast, 1)  ; to keep track of unique objects within top object
 
 enum := ast._newenum()
 while enum[key, value]
 {
   if reserved["seen" . &value]
     continue  ; don't copy repeat objects (circular references)
string .= key . "
" . objPrint(value, reserved)
   string .= objPrint(value, reserved)
 }
 return "(" string ")"

}


objFlatten(ast) {

 if !isobject(ast)
   return ast
 
 flat := object() ; flat object
 
 enum := ast._newenum()
 while enum[key, value]
 {
   if !isobject(value)
     flat._Insert(value)
   else
   {
     next := objFlatten(value)
     loop % next._MaxIndex()
     flat._Insert(next[A_Index])
     
   }
 }
 return flat

}</lang>

C

Example in C using a quick and dirty implementation of lists as a singly-linked list of structs.

List header file: <lang c>// list.h

  1. ifndef __LIST_H__
  2. define __LIST_H__

// A quick and dirty list implementation. // Not recommended for use in production software.

// Types typedef enum {

 NUMBER,
 LIST

} ItemType;

typedef struct _Item {

 ItemType type;
 union {
   int number;
   struct {
     struct _Item *head;
     struct _Item *tail;
   } list;
 };
 struct _Item *next;

} Item;

// Functions Item *NewListItem(Item *item1, ...); Item *NewNumberItem(int number); void PrintItem(Item *item); void DeleteItem(Item *item);

void Flatten(Item *item);

  1. endif // __LIST_H__</lang>

List functions: <lang c>// list.c

  1. include <stdarg.h>
  2. include <stdlib.h>
  3. include <stdio.h>
  4. include "list.h"

// Create (malloc) a new number item struct. Item *NewNumberItem(int number) {

 Item *pItem = (Item *)malloc(sizeof(Item));
 
 pItem->type   = NUMBER;
 pItem->number = number;
 pItem->next   = NULL;
 return pItem;

}

// Create (malloc) a new list item struct, and (optionally) // populate it with the given list of items. Note, we use // a variable args function for this to make constructing // a new list easier. Make sure to terminate the args list // with a NULL. NewListItem(NULL) creates an empty list. Item *NewListItem(Item *item1, ...) {

 Item *pList = (Item *)malloc(sizeof(Item));
 Item *pItem = item1;
 va_list items;
 pList->type      = LIST;
 pList->list.head = NULL;
 pList->list.tail = NULL;
 pList->next      = NULL;
 // Warning: Not sure this will work
 // on all compilers when item1 is NULL.
 // This example uses MSVC 6.
 va_start(items, item1);
 while(pItem != NULL) 
 {
   if (pList->list.tail != NULL)
     pList->list.tail->next = pItem;
   else
     pList->list.head = pItem;
   pList->list.tail = pItem;
   pItem->next = NULL;
   pItem = va_arg(items, Item *);
 }
 va_end(items);
 return pList;

}

// Print out a list on a single line, as in: // [[1],2,[[3,4],5],[[[]]],[[[6]]],7,8,[]] void PrintItem(Item *item) {

 Item *subItem;
 if (item->type == LIST) 
 {
   printf("[");
   subItem = item->list.head;
   while (subItem != NULL) 
   {
     if (subItem != item->list.head)
       printf(",");
     PrintItem(subItem);
     subItem = subItem->next;
   }
   printf("]");
 } 
 else 
   printf("%d", item->number);

}

// Delete an item. Recurse if necessary to delete sublists. void DeleteItem(Item *item) {

 Item *subItem;
 if (item->type == LIST) 
 {
   while (item->list.head != NULL) 
   {
     subItem = item->list.head;
     item->list.head = subItem->next;
     DeleteItem(subItem);
   }
 }
 free(item);

}</lang>

The Flatten algorithm (with lots comments since this is a one-off lists implementation): <lang c>// flatten.c

  1. include <stdlib.h>
  2. include "list.h"

void Flatten(Item *item) {

 Item *subItem, *prevItem, *nextItem;
 // Flatten is only meaningful for list items.
 if (item->type == LIST) 
 {
   prevItem = NULL;
   subItem  = item->list.head;
   // Flatten all subitems one at a time.
   while (subItem != NULL) 
   {
     // Again, only list items need to be flattened.
     if (subItem->type == LIST) 
     {
       // Flatten the sublist.
       Flatten(subItem);
       // If the now-flattened sublist is non-empty, its first item
       // will now be the next item in the parent list. If the sublist
       // is empty, the next item in the parent list will be the item
       // after the sublist.
       if (subItem->list.head != NULL) nextItem = subItem->list.head;
       else                            nextItem = subItem->next;
       // Update the previous item's next pointer (or the parent list's
       // head pointer, if the sublist we are deleting was the first 
       // item in the parent list) so that it no longer points to the 
       // sublist that we are about to delete. It should now point to
       // nextItem, which we determined above.
       if (prevItem != NULL) prevItem->next  = nextItem;
       else                  item->list.head = nextItem;
       // If the sublist was non-empty, then we now need to update
       // our prevItem pointer to point to the last item in the sublist.
       if (subItem->list.tail != NULL) prevItem = subItem->list.tail;
       // If the sublist we are about to delete is the last item in the
       // parent list, we need to update the parent list's tail pointer.
       if (subItem == item->list.tail) item->list.tail = prevItem;
       // Lastly, we need to make sure that prevItem's next pointer
       // points to the item immediately following the doomed sublist.
       if (prevItem != NULL) prevItem->next = subItem->next;
       // Finally, destroy the sublist.
       free(subItem);
       // Now update the subItem pointer to pick up where we left off
       // in the parent list.
       if (prevItem != NULL) subItem = prevItem->next;
       else                  subItem = NULL;
     }
     else
     {
       // Nothing to do for number items. Just skip past them.
       prevItem = subItem;
       subItem  = subItem->next;
     }
   }
 }

}</lang>

The test program: <lang c>// main.c

  1. include <stdlib.h>
  2. include <stdio.h>
  3. include <stdarg.h>
  4. include "list.h"

// Short-hand to make list construction somewhat less cumbersome.

  1. define L NewListItem
  2. define N NewNumberItem

int main(int argc, char **argv) {

 Item *list = L( L(N(1),NULL), N(2), L( L(N(3),N(4),NULL), N(5), NULL), 
                 L( L( L(NULL), NULL), NULL), L( L( L(N(6), NULL), NULL), NULL), 
                 N(7), N(8), L(NULL), NULL );
 printf("Original List : ");
 PrintItem(list);
 printf("\n");
 Flatten(list);
 printf("Flattened List: ");
 PrintItem(list);
 printf("\n");
 DeleteItem(list);
 return 0;

}</lang>

Output:

Original List : [[1],2,[[3,4],5],[[[]]],[[[6]]],7,8,[]]
Flattened List: [1,2,3,4,5,6,7,8]

C++

<lang cpp>#include <list>

  1. include <boost/any.hpp>

typedef std::list<boost::any> anylist;

void flatten(std::list<boost::any>& list) {

 typedef anylist::iterator iterator;
 iterator current = list.begin();
 while (current != list.end())
 {
   if (current->type() == typeid(anylist))
   {
     iterator next = current;
     ++next;
     list.splice(next, boost::any_cast<anylist&>(*current));
     next = current;
     ++next;
     list.erase(current);
     current = next;
   }
   else
     ++current;
 }

}</lang>

Use example:

Since C++ currently doesn't have nice syntax for initializing lists, this includes a simple parser to create lists of integers and sublists. Also, there's no standard way to output this type of list, so some output code is added as well. <lang cpp>#include <cctype>

  1. include <iostream>

// ******************* // * the list parser * // *******************

void skipwhite(char const** s) {

 while (**s && std::isspace((unsigned char)**s))
 {
   ++*s;
 }

}

anylist create_anylist_i(char const** s) {

 anylist result;
 skipwhite(s);
 if (**s != '[')
   throw "Not a list";
 ++*s;
 while (true)
 {
   skipwhite(s);
   if (!**s)
     throw "Error";
   else if (**s == ']')
   {
     ++*s;
     return result;
   }
   else if (**s == '[')
     result.push_back(create_anylist_i(s));
   else if (std::isdigit((unsigned char)**s))
   {
     int i = 0;
     while (std::isdigit((unsigned char)**s))
     {
       i = 10*i + (**s - '0');
       ++*s;
     }
     result.push_back(i);
   }
   else
     throw "Error";
   skipwhite(s);
   if (**s != ',' && **s != ']')
     throw "Error";
   if (**s == ',')
     ++*s;
 }

}

anylist create_anylist(char const* i) {

 return create_anylist_i(&i);

}

// ************************* // * printing nested lists * // *************************

void print_list(anylist const& list);

void print_item(boost::any const& a) {

 if (a.type() == typeid(int))
   std::cout << boost::any_cast<int>(a);
 else if (a.type() == typeid(anylist))
   print_list(boost::any_cast<anylist const&>(a));
 else
   std::cout << "???";

}

void print_list(anylist const& list) {

 std::cout << '[';
 anylist::const_iterator iter = list.begin();
 while (iter != list.end())
 {
   print_item(*iter);
   ++iter;
   if (iter != list.end())
     std::cout << ", ";
 }
 std::cout << ']';

}

// *************************** // * The actual test program * // ***************************

int main() {

 anylist list =
   create_anylist("[[1], 2, [[3,4], 5], [[[]]], [[[6]]], 7, 8, []]");
 print_list(list);
 std::cout << "\n";
 flatten(list);
 print_list(list);
 std::cout << "\n";

}</lang> The output of this program is

[[1], 2, [[3, 4], 5], [[[]]], [[[6]]], 7, 8, []]
[1, 2, 3, 4, 5, 6, 7, 8]

C#

Works with: C# version 3+

Actual Workhorse code <lang csharp> using System; using System.Collections; using System.Linq;

namespace RosettaCodeTasks { static class FlattenList { public static ArrayList Flatten(this ArrayList List) { ArrayList NewList = new ArrayList ( );

NewList.AddRange ( List );

while ( NewList.OfType<ArrayList> ( ).Count ( ) > 0 ) { int index = NewList.IndexOf ( NewList.OfType<ArrayList> ( ).ElementAt ( 0 ) ); ArrayList Temp = (ArrayList)NewList[index]; NewList.RemoveAt ( index ); NewList.InsertRange ( index, Temp ); }

return NewList; } } } </lang>

Method showing population of arraylist and usage of flatten method <lang csharp> using System; using System.Collections;

namespace RosettaCodeTasks { class Program { static void Main ( string[ ] args ) {

ArrayList Parent = new ArrayList ( ); Parent.Add ( new ArrayList ( ) ); ((ArrayList)Parent[0]).Add ( 1 ); Parent.Add ( 2 ); Parent.Add ( new ArrayList ( ) ); ( (ArrayList)Parent[2] ).Add ( new ArrayList ( ) ); ( (ArrayList)( (ArrayList)Parent[2] )[0] ).Add ( 3 ); ( (ArrayList)( (ArrayList)Parent[2] )[0] ).Add ( 4 ); ( (ArrayList)Parent[2] ).Add ( 5 ); Parent.Add ( new ArrayList ( ) ); ( (ArrayList)Parent[3] ).Add ( new ArrayList ( ) ); ( (ArrayList)( (ArrayList)Parent[3] )[0] ).Add ( new ArrayList ( ) ); Parent.Add ( new ArrayList ( ) ); ( (ArrayList)Parent[4] ).Add ( new ArrayList ( ) ); ( (ArrayList)( (ArrayList)Parent[4] )[0] ).Add ( new ArrayList ( ) );

( (ArrayList)( (ArrayList)( (ArrayList)( (ArrayList)Parent[4] )[0] )[0] ) ).Add ( 6 ); Parent.Add ( 7 ); Parent.Add ( 8 ); Parent.Add ( new ArrayList ( ) );


foreach ( Object o in Parent.Flatten ( ) ) { Console.WriteLine ( o.ToString ( ) ); } }

} }

</lang>

Clojure

The following returns a lazy sequence of the flattened data structure. <lang lisp>(defn flatten [coll]

 (lazy-seq
   (when-let [s  (seq coll)]
     (if (coll? (first s))
       (concat (flatten (first s)) (flatten (rest s)))
       (cons (first s) (flatten (rest s)))))))</lang>

An alternative approach (from clojure.contrib.seq-utils).

<lang lisp>(defn flatten [x]

 (filter (complement sequential?)
         (rest (tree-seq sequential? seq x))))</lang>

Common Lisp

<lang lisp>(defun flatten (tree)

 (let ((result '()))
   (labels ((scan (item)
              (if (listp item)
                (map nil #'scan item)
                (push item result))))
     (scan tree))
   (nreverse result)))</lang>

While this is a common homework problem in Common Lisp, it should be noted that it is typically a mistake to use it in a realistic program; it is almost always easier to rewrite the program such that it does not generate the deeply-nested lists in the first place. In particular, note that flattening means that none of the values stored in the nested-list-structure can be a list (a cons or nil) itself. For example, producing and flattening a tree of boolean values would not do the right thing, since false = nil, a list.

D

There are many ways to implement this in D. This version minimizes heap activity using a tagged union. A similar object-oriented version too is possible.

The example has been modified so it

Works with: D version 2

the same way as it

Works with: D version 1

using

Library: tango

<lang d>version(Tango) {

 import tango.io.Stdout;
 import tango.io.device.Array;
 import tango.io.stream.Format;

} else {

 import std.stdio : writeln;
 import std.conv : to;

}

struct TreeList(T) {

   alias TreeList!(T) MyT;
   bool isArr = true; // contains an arr on default
   union {
       MyT[] arr;
       T data;
   }   
   static MyT opCall(Types...)(Types items) {
       MyT result;
       foreach (i, el; items)
           static if (is(Types[i] == T)) {
               MyT item;
               item.isArr = false;
               item.data = el;
               result.arr ~= item;
           } else
               result.arr ~= el;

           return result;
   }

   // this is better as a general free function
   MyT flatten() {
       MyT result;

       if (this.isArr) {
           foreach (el; this.arr)
               result.arr ~= el.flatten().arr;
       } else {
           version (D_Version2) {
               result.arr ~= this;

           } else {
               result.arr ~= *this;
           }
       }

       return result;
   }

   version(Tango) {
       char[] toString() {
           auto bf = new Array(1024);
           auto f = new FormatOutput!(char) (bf);
           if (isArr) {
               f(arr);
           } else {
               f(data);
           }
           return cast(char[])bf.slice;
       }
   }

   version (D_Version2) {
       string toString() {
           if (isArr) return to!(string)(arr, "[", ", ", "]");
           else return to!(string)(data);
       }
   }

}

void main() {

   alias TreeList!(int) L; // 12 bytes if T is int
   auto list = L(L(1), 2, L(L(3,4), 5), L(L(L())), L(L(L(6))), 7, 8, L());

   version (Tango) {
       Stdout (list).newline;
       Stdout (list.flatten()).newline;

   } else {
       writeln(list);
       writeln(list.flatten());
   }

}</lang> Output:

[[1], 2, [[3, 4], 5], [[[]]], [[[6]]], 7, 8, []]
[1, 2, 3, 4, 5, 6, 7, 8]

E

<lang e>def flatten(nested) {

   def flat := [].diverge()
   def recur(x) {
       switch (x) {
           match list :List { for elem in list { recur(elem) } }
           match other      { flat.push(other) }
       }
   }
   recur(nested)
   return flat.snapshot()

}</lang>

<lang e>? flatten([[1], 2, [[3,4], 5], [[[]]], [[[6]]], 7, 8, []])

  1. value: [1, 2, 3, 4, 5, 6, 7, 8]</lang>

Erlang

There's a standard function (lists:flatten/2) that does it more efficiently, but this is the cleanest implementation you could have; <lang Erlang>flatten([]) -> []; flatten([H|T]) -> flatten(H) ++ flatten(T); flatten(H) -> [H].</lang>

Factor

   USE: sequences.deep
   ( scratchpad ) { { 1 } 2 { { 3 4 } 5 } { { { } } } { { { 6 } } } 7 8 { } } flatten .
   { 1 2 3 4 5 6 7 8 }

Groovy

List.flatten() is a Groovy built-in that returns a flattened copy of the source list:

<lang groovy>assert [[1], 2, [[3,4], 5], [[[]]], [[[6]]], 7, 8, []].flatten() == [1, 2, 3, 4, 5, 6, 7, 8]</lang>

Haskell

In Haskell we have to interpret this structure as an algebraic data type.

<lang Haskell>import Data.Tree

-- [[1], 2, [[3,4], 5], [[[]]], [[[6]]], 7, 8, []] -- implemented as multiway tree:

-- Data.Tree represents trees where nodes have values too, unlike the trees in our problem. -- so we use a list as that value, where a node will have an empty list value, -- and a leaf will have a one-element list value and no subtrees list :: Tree [Int] list = Node [] [

               Node [] [Node [1] []],
               Node [2] [],
               Node [] [
                        Node [] [ Node [3] [],Node [4] []],
                        Node [5] []
                       ],
               Node [] [Node [] [Node [] []]],
               Node [] [Node [] [Node [6] []]],
               Node [7] [],
               Node [8] [],
               Node [] []
               ]

flattenList = concat.flatten</lang> Flattening the list:

*Main> flattenList list
[1,2,3,4,5,6,7,8]

Alternately: <lang haskell>data Tree a = Leaf a | Node [Tree a]

flatten :: Tree a -> [a] flatten (Leaf x) = [x] flatten (Node xs) = concatMap flatten xs

main = print $ flatten $ Node [Node [Leaf 1],

                              Leaf 2,
                              Node [Node [Leaf 3, Leaf 4], Leaf 5],
                              Node [Node [Node []]],
                              Node [Node [Node [Leaf 6]]],
                              Leaf 7,
                              Leaf 8,
                              Node []]

-- output: [1,2,3,4,5,6,7,8]</lang>

Yet another choice, custom data structure, efficient lazy flattening:

<lang haskell>data NestedList a = NList [NestedList a] | Entry a

flatten :: NestedList a -> [a] flatten nl = flatten' nl []

 where
   -- By passing through a list which the results will be preprended to we allow efficient lazy evaluation
   flatten' :: NestedList a -> [a] -> [a]
   flatten' (Entry a) cont = a:cont
   flatten' (NList entries) cont = foldr flatten' cont entries

example :: NestedList Int example = NList [ NList [Entry 1], Entry 2, NList [NList [Entry 3, Entry 4], Entry 5], NList [NList [NList []]], NList [ NList [ NList [Entry 6]]], Entry 7, Entry 8, NList []]

main :: IO () main = print $ flatten example

-- output [1,2,3,4,5,6,7,8]</lang>

Icon and Unicon

Icon

The following procedure solves the task using a string representation of nested lists and cares not if the list is well formed or not. <lang Icon>link strings # for compress,deletec,pretrim

procedure sflatten(s) # uninteresting string solution return pretrim(trim(compress(deletec(s,'[ ]'),',') ,','),',') end</lang>

The solution uses several procedures from strings in the IPL

This procedure is more in the spirit of the task handling actual lists rather than representations. It uses a recursive approach using some of the built-in list manipulation functions and operators. <lang Icon>procedure flatten(L) # in the spirt of the problem a structure local l,x

l := [] every x := !L do

  if type(x) == "list" then l |||:= flatten(x)
  else put(l,x)

return l end</lang>

Finally a demo routine to drive these and a helper to show how it works. <lang Icon>procedure main() write(sflatten(" [[1], 2, [[3,4], 5], [[[]]], [[[6]]], 7, 8, []]")) writelist(flatten( [[1], 2, [[3,4], 5], [[[]]], [[[6]]], 7, 8, []])) end

procedure writelist(L) writes("[") every writes(" ",image(!L)) write(" ]") return end</lang>

Unicon

This Icon solution works in Unicon.

Ioke

<lang ioke>iik> [[1], 2, [[3,4], 5], [[[]]], [[[6]]], 7, 8, []] flatten [[1], 2, [[3,4], 5], [[[]]], [[[6]]], 7, 8, []] flatten +> [1, 2, 3, 4, 5, 6, 7, 8]</lang>

J

Solution: <lang j>flatten =: [: ; <S:0</lang>

The primitive ; removes one level of nesting.

<S:0 takes an arbitrarily nested list and puts everything one level deep.

[: is glue, here.

We do not use ; by itself because it requires that all of the contents be the same type and nested items have a different type from unnested items.

We do not use ]S:0 (which puts everything zero levels deep) because it assembles its results as items of a list, which means that short items will be padded to be equal to the largest items, and that is not what we want here.

Example: <lang j> NB. create and display nested noun li

  ]li =.  (<1) ; 2; ((<3; 4); 5) ; ((<a:)) ; ((<(<6))) ; 7; 8; <a:</lang>

<lang text>┌───┬─┬───────────┬────┬─────┬─┬─┬──┐ │┌─┐│2│┌───────┬─┐│┌──┐│┌───┐│7│8│┌┐│ ││1││ ││┌─────┐│5│││┌┐│││┌─┐││ │ ││││ │└─┘│ │││┌─┬─┐││ │││││││││6│││ │ │└┘│ │ │ ││││3│4│││ │││└┘│││└─┘││ │ │ │ │ │ │││└─┴─┘││ ││└──┘│└───┘│ │ │ │ │ │ ││└─────┘│ ││ │ │ │ │ │ │ │ │└───────┴─┘│ │ │ │ │ │ └───┴─┴───────────┴────┴─────┴─┴─┴──┘</lang>

(Note: if you are not seeing rectangular boxes here, that is because your browser either does not support line drawing characters or is using line drawing characters from a different font than your numeric characters.)

<lang j> flatten li 1 2 3 4 5 6 7 8</lang>

Alternative Solution:
The previous solution can be generalized to flatten the nesting and shape for a list of arbitrary values that include arrays of any rank: <lang j>flatten2 =: [: ; <@,S:0</lang>

Example: <lang j> ]li2 =. (<1) ; 2; ((<3;4); 5 + i.3 4) ; ((<a:)) ; ((<(<17))) ; 18; 19; <a:</lang> <lang text>┌───┬─┬─────────────────────┬────┬──────┬──┬──┬──┐ │┌─┐│2│┌───────┬───────────┐│┌──┐│┌────┐│18│19│┌┐│ ││1││ ││┌─────┐│ 5 6 7 8│││┌┐│││┌──┐││ │ ││││ │└─┘│ │││┌─┬─┐││ 9 10 11 12│││││││││17│││ │ │└┘│ │ │ ││││3│4│││13 14 15 16│││└┘│││└──┘││ │ │ │ │ │ │││└─┴─┘││ ││└──┘│└────┘│ │ │ │ │ │ ││└─────┘│ ││ │ │ │ │ │ │ │ │└───────┴───────────┘│ │ │ │ │ │ └───┴─┴─────────────────────┴────┴──────┴──┴──┴──┘</lang> <lang j> flatten2 li 1 2 3 4 5 6 7 8

  flatten2 li2

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19</lang>

Java

Works with: Java version 1.5+

<lang java5>import java.util.LinkedList; import java.util.List; import java.util.Arrays;

public class Flatten {

 public static List<Object> flatten(List<?> list){
   List<Object> retVal = new LinkedList<Object>();
   for(Object item:list){
     if(item instanceof List){
       retVal.addAll(flatten((List)item));
     }else{
       retVal.add(item);
     }
   }
   return retVal;
 }
 public static void main(String[] args){
   List<Object> test = Arrays.<Object>asList(
                         Arrays.<Object>asList(1),
                         2,
                         Arrays.<Object>asList(
                           Arrays.<Object>asList(3,4),
                           5
                         ),
                         Arrays.<Object>asList(
                           Arrays.<Object>asList(
                             Arrays.<Object>asList()
                           )
                         ),
                         Arrays.<Object>asList(
                           Arrays.<Object>asList(
                             Arrays.<Object>asList(6)
                           )
                         ),
                         7,
                         8,
                         Arrays.<Object>asList()
                       );
   System.out.println(test);
   System.out.println(flatten(test));
 }

}</lang> Output:

[[1], 2, [[3, 4], 5], [[[]]], [[[6]]], 7, 8, []]
[1, 2, 3, 4, 5, 6, 7, 8]

JavaScript

Library: Prototype
Works with: a browser

<lang javascript><script type="text/javascript" src="/path/to/prototype.js"></script> <script type="text/javascript">

  var a = [[1], 2, [[3,4], 5], [[[]]], [[[6]]], 7, 8, []];

document.write("

before

"); a.each(function(e){document.write("

" + e + " " + typeof(e) + "

")});

  var f = a.flatten();

document.write("

after

"); f.each(function(e){document.write("

" + e + " " + typeof(e) + "

")});

</script></lang> output:

before

1 object
2 number
3,4,5 object
object
6 object
7 number
8 number
object

after

1 number
2 number
3 number
4 number
5 number
6 number
7 number
8 number

Lua

<lang lua>function flatten(list)

 if type(list) ~= "table" then return {list} end
 local flat_list = {}
 for _, elem in ipairs(list) do
   for _, val in ipairs(flatten(elem)) do
     flat_list[#flat_list + 1] = val
   end
 end
 return flat_list

end

test_list = {{1}, 2, {{3,4}, 5}, {{{}}}, {{{6}}}, 7, 8, {}}

print(table.concat(flatten(test_list), ","))</lang>

<lang logo>to flatten :l

 if not list? :l [output :l]
 if empty? :l [output []]
 output sentence flatten first :l flatten butfirst :l

end

using a template iterator (map combining results into a sentence)

to flatten :l

 output map.se [ifelse or not list? ? empty? ? [?] [flatten ?]] :l

end

make "a [[1] 2 [[3 4] 5] [[[]]] [[[6]]] 7 8 []] show flatten :a</lang>

Mathematica

<lang Mathematica>Flatten@{{1}, 2, {{3, 4}, 5}, {{{}}}, {{{6}}}, 7, 8, {}}</lang>

Objective-C

Works with: Cocoa

and

Works with: GNUstep

<lang objc>#import <Foundation/Foundation.h>

@interface NSArray (FlattenExt) -(NSArray *)flatten; @end

@implementation NSArray (FlattenExt) -(NSArray *)flatten {

 NSMutableArray *r = [NSMutableArray new];
 NSEnumerator *en = [self objectEnumerator];
 id o;
 while ( (o = [en nextObject]) ) {
   if ( [o isKindOfClass: [NSArray class]] ) {
     [r addObjectsFromArray: [o flatten]];
   } else {
     if ( o != [NSNull null] ) 

[r addObject: o];

   }
 }
 return [NSArray arrayWithArray: r];

} @end

int main() {

 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 
 NSArray *p = [NSArray 

arrayWithObjects: [NSArray arrayWithObjects: [NSNumber numberWithInt: 1], nil], [NSNumber numberWithInt: 2], [NSArray arrayWithObjects: [NSArray arrayWithObjects: [NSNumber numberWithInt: 3], [NSNumber numberWithInt: 4], nil], [NSNumber numberWithInt: 5], nil], [NSArray arrayWithObjects: [NSArray arrayWithObjects: [NSArray arrayWithObject: [NSNull null]], nil], nil], [NSArray arrayWithObjects: [NSArray arrayWithObjects: [NSArray arrayWithObjects: [NSNumber numberWithInt: 6], nil], nil], nil], [NSNumber numberWithInt: 7], [NSNumber numberWithInt: 8], [NSArray arrayWithObject: [NSNull null]], nil];

 NSArray *f = [p flatten];
 NSEnumerator *e = [f objectEnumerator];
 id o;
 while( (o = [e nextObject]) )
 {
   NSLog(@"%d", [o intValue]);
 }


 [pool drain];
 return 0;

}</lang>

An alternative solution

Works with: Cocoa

<lang objc2>#import <Foundation/Foundation.h>

@interface NSArray (FlattenExt) @property (nonatomic, readonly) NSArray *flattened; @end

@implementation NSArray (FlattenExt) -(NSArray *) flattened {

   NSMutableArray *flattened = [[NSMutableArray alloc] initWithCapacity:self.count];
   
   for (id object in self) {
       if ([object isKindOfClass:[NSArray class]])
           [flattened addObjectsFromArray:((NSArray *)object).flattened];
       else if (object != [NSNull null])
           [flattened addObject:object];
   }
   
   return [flattened autorelease];

} @end

int main(int argc, char **argv) {

   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   NSArray *unflattened = [NSArray arrayWithObjects:[NSArray arrayWithObject:[NSNumber numberWithInteger:1]],
                          [NSNumber numberWithInteger:2],
                          [NSArray arrayWithObjects:[NSArray arrayWithObjects:[NSNumber numberWithInteger:3], [NSNumber numberWithInteger:4], nil],
                          [NSNumber numberWithInteger:5], nil],
                          [NSArray arrayWithObject:[NSArray arrayWithObject:[NSArray arrayWithObject:[NSNull null]]]],
                          [NSArray arrayWithObject:[NSArray arrayWithObject:[NSArray arrayWithObject:[NSNumber numberWithInteger:6]]]],
                          [NSNumber numberWithInteger:7],
                          [NSNumber numberWithInteger:8],
                          [NSArray arrayWithObject:[NSNull null]], nil];
   
   for (id object in unflattened.flattened)
       NSLog(@"%d", [object integerValue]);
   
   [pool drain];
   
   return 0;

}</lang>

OCaml

<lang ocaml># let flatten = List.concat ;; val flatten : 'a list list -> 'a list = <fun>

  1. let li = [[1]; 2; [[3;4]; 5]; [[[]]]; [[[6]]]; 7; 8; []] ;;
               ^^^

Error: This expression has type int but is here used with type int list

  1. (* use another data which can be accepted by the type system *)
 flatten [[1]; [2; 3; 4]; []; [5; 6]; [7]; [8]] ;;

- : int list = [1; 2; 3; 4; 5; 6; 7; 8]</lang>

Since OCaml is statically typed, it is not possible to have a value that could be both a list and a non-list. Instead, we can use an algebraic datatype:

<lang ocaml># type 'a tree = Leaf of 'a | Node of 'a tree list ;; type 'a tree = Leaf of 'a | Node of 'a tree list

  1. let rec flatten = function
    Leaf x -> [x]
  | Node xs -> List.concat (List.map flatten xs) ;;

val flatten : 'a tree -> 'a list = <fun>

  1. flatten (Node [Node [Leaf 1]; Leaf 2; Node [Node [Leaf 3; Leaf 4]; Leaf 5]; Node [Node [Node []]]; Node [Node [Node [Leaf 6]]]; Leaf 7; Leaf 8; Node []]) ;;

- : int list = [1; 2; 3; 4; 5; 6; 7; 8]</lang>

Oz

Oz has a standard library function "Flatten": <lang oz>{Show {Flatten [[1] 2 [[3 4] 5] nil [[[6]]] 7 8 nil]}}</lang> A simple, non-optimized implementation could look like this: <lang oz>fun {Flatten2 Xs}

  case Xs of nil then nil
  [] X|Xr then
     {Append {Flatten2 X} {Flatten2 Xr}}
  else [Xs]
  end

end </lang>

Perl

<lang perl>sub flatten {

   map { ref eq 'ARRAY' ? flatten(@$_) : $_ } @_

}

my @lst = ([1], 2, [[3,4], 5], [[[]]], [[[6]]], 7, 8, []); print flatten(@lst), "\n";</lang>

Perl 6

Works with: Rakudo version #22 "Thousand Oaks"

<lang perl6>multi flatten (@a) { map { flatten $^x }, @a } multi flatten ($x) { $x }</lang>

PHP

<lang php>/* Note: This code is only for PHP 4.

  It won't work on PHP 5 due to the change in behavior of array_merge(). */

while (array_filter($lst, 'is_array'))

   $lst = call_user_func_array('array_merge', $lst);</lang>

Explanation: while $lst has any elements which are themselves arrays (i.e. $lst is not flat), we merge the elements all together (in PHP 4, array_merge() treated non-array arguments as if they were 1-element arrays; PHP 5 array_merge() no longer allows non-array arguments.), thus flattening the top level of any embedded arrays. Repeat this process until the array is flat.

Recursive

<lang php><?php function flatten($ary) {

   $result = array();
   foreach ($ary as $x) {
       if (is_array($x))
           // append flatten($x) onto $result
           array_splice($result, count($result), 0, flatten($x));
       else
           $result[] = $x;
   }
   return $result;

}

$lst = array(array(1), 2, array(array(3, 4), 5), array(array(array())), array(array(array(6))), 7, 8, array()); var_dump(flatten($lst)); ?></lang>

Non-recursive

Function flat is iterative and flattens the array in-place. <lang php><?php function flat(&$ary) { // argument must be by reference or array will just be copied

   for ($i = 0; $i < count($ary); $i++) {
       while (is_array($ary[$i])) {
           array_splice($ary, $i, 1, $ary[$i]);
       }
   }

}

$lst = array(array(1), 2, array(array(3, 4), 5), array(array(array())), array(array(array(6))), 7, 8, array()); flat($lst); var_dump($lst); ?></lang>

PicoLisp

<lang PicoLisp>(de flatten (X)

  (make                               # Build a list
     (recur (X)                       # recursively over 'X'
        (if (atom X)
           (link X)                   # Put atoms into the result
           (mapc recurse X) ) ) ) )   # or recurse on sub-lists</lang>

or a more succint way using fish:

<lang PicoLisp>(de flatten (X)

  (fish atom X) )</lang>

PL/I

<lang PL/I> list = translate (list, ' ', '[]' ); list = '[' || list || ']'; </lang>

Prolog

<lang Prolog> flatten([], []). flatten(E, [E]) :- atom(E). flatten([E|T], F) :-

 flatten(E, Ef),
 flatten(T, Tf),
 append(Ef, Tf, F), !.

</lang>

Python

Recursive

Function flatten is recursive and preserves its argument: <lang python>>>> def flatten(lst): return sum( ([x] if not isinstance(x, list) else flatten(x) for x in lst), [] )

>>> lst = [[1], 2, [[3,4], 5], [[[]]], [[[6]]], 7, 8, []] >>> flatten(lst) [1, 2, 3, 4, 5, 6, 7, 8]</lang>

Non-recursive

Function flat is iterative and flattens the list in-place. It follows the Python idiom of returning None when acting in-place: <lang python>>>> def flat(lst):

   i=0
   while i<len(lst):
       while True:
           try:
               lst[i:i+1] = lst[i]
           except (TypeError, IndexError):
               break
       i += 1
       

>>> lst = [[1], 2, [[3,4], 5], [[[]]], [[[6]]], 7, 8, []] >>> flat(lst) >>> lst [1, 2, 3, 4, 5, 6, 7, 8]</lang>

Generative

This method shows a solution using Python generators.

flatten is a generator that yields the non-list values of its input in order. The primary advantage of generators is that there are no temporary values needed. For large input, this can reduce memory usage dramatically.

The generator is converted back to a list before printing.

<lang python>>>> def flatten(lst):

    for x in lst:
        if isinstance(x, list):
            for x in flatten(x):
                yield x
        else:
            yield x


>>>lst = [[1], 2, [[3,4], 5], [[[]]], [[[6]]], 7, 8, []] >>>print list(flatten(lst)) [1, 2, 3, 4, 5, 6, 7, 8]</lang>

R

<lang R>x <- list(list(1), 2, list(list(3, 4), 5), list(list(list())), list(list(list(6))), 7, 8, list())

unlist(x)</lang>


REBOL

<lang rebol> flatten: func [

   "Flatten the block in place."
   block [any-block!]

][

   parse block [
       any [block: any-block! (change/part block first block 1) :block | skip]
   ]
   head block

] </lang>

Sample:

>> flatten [[1] 2 [[3 4] 5] [[[]]] [[[6]]] 7 8 []]
== [1 2 3 4 5 6 7 8]

Ruby

flatten is a built-in method of Arrays <lang ruby>flat = [[1], 2, [[3,4], 5], [[[]]], [[[6]]], 7, 8, []].flatten p flat # => [1, 2, 3, 4, 5, 6, 7, 8]</lang>

Scala

<lang scala>def flatList(l: List[_]): List[Any] = l match {

 case Nil => Nil
 case (head: List[_]) :: tail => flatList(head) ::: flatList(tail)
 case head :: tail => head :: flatList(tail)

}</lang>

Sample:

scala> List(List(1), 2, List(List(3, 4), 5), List(List(List())), List(List(List(6))), 7, 8, List())
res10: List[Any] = List(List(1), 2, List(List(3, 4), 5), List(List(List())), List(List(List(6))), 7, 8, List())

scala> flatList(res10)
res12: List[Any] = List(1, 2, 3, 4, 5, 6, 7, 8)

Scheme

<lang scheme>> (define (flatten x)

   (cond ((null? x) '())
         ((not (pair? x)) (list x))
         (else (append (flatten (car x))
                       (flatten (cdr x))))))

> (flatten '((1) 2 ((3 4) 5) ((())) (((6))) 7 8 ())) (1 2 3 4 5 6 7 8)</lang>

Slate

<lang slate>s@(Sequence traits) flatten [

 [| :out | s flattenOn: out] writingAs: s

].

s@(Sequence traits) flattenOn: w@(WriteStream traits) [

 s do: [| :value |
   (value is: s)
     ifTrue: [value flattenOn: w]
     ifFalse: [w nextPut: value]].

].</lang>

Smalltalk

Works with: GNU Smalltalk

<lang smalltalk>OrderedCollection extend [

 flatten [ |f|
   f := OrderedCollection new.
   self do: [ :i |
     i isNumber
       ifTrue: [ f add: i ]
       ifFalse: [ |t|
         t := (OrderedCollection withAll: i) flatten.
         f addAll: t
       ]
   ].
   ^ f
 ]

].


|list| list := OrderedCollection

         withAll: { {1} . 2 . { {3 . 4} . 5 } .
                    {{{}}} . {{{6}}} . 7 . 8 . {} }.

(list flatten) printNl.</lang>

Suneido

<lang suneido>ob = [[1], 2, [[3,4], 5], [[[]]], [[[6]]], 7, 8, []] ob.Flatten()</lang>

Output:

#(1, 2, 3, 4, 5, 6, 7, 8)

Tcl

<lang tcl>proc flatten list {

   for {set old {}} {$old ne $list} {} {
       set old $list
       set list [join $list]
   }
   return $list

}

puts [flatten {{1} 2 {{3 4} 5} {{{}}} {{{6}}} 7 8 {}}]

  1. ===> 1 2 3 4 5 6 7 8</lang>

Note that because lists are not syntactically distinct from strings, it is probably a mistake to use this procedure with real (especially non-numeric) data. Also note that there are no parentheses around the outside of the list when printed; this is just a feature of how Tcl regards lists, and the value is a proper list (it can be indexed into with lindex, iterated over with foreach, etc.)

Another implementation that's slightly more terse:

<lang tcl>proc flatten {data} {

   while { $data != [set data [join $data]] } { }
   return $data

} puts [flatten {{1} 2 {{3 4} 5} {{{}}} {{{6}}} 7 8 {}}]

  1. ===> 1 2 3 4 5 6 7 8</lang>

TI-89 BASIC

There is no nesting of lists or other data structures in TI-89 BASIC, short of using variable names as pointers.

Trith

<lang trith>[[1] 2 [[3 4] 5] [[[]]] [[[6]]] 7 8 []] flatten</lang>

VBScript

Working on embedded arrays as that's about the closest we get to lists.

Implementation

<lang vb> class flattener dim separator

sub class_initialize separator = "," end sub

private function makeflat( a ) dim i dim res for i = lbound( a ) to ubound( a ) if isarray( a( i ) ) then res = res & makeflat( a( i ) ) else res = res & a( i ) & separator end if next makeflat = res end function

public function flatten( a ) dim res res = makeflat( a ) res = left( res, len( res ) - len(separator)) res = split( res, separator ) flatten = res end function

public property let itemSeparator( c ) separator = c end property end class </lang>

Invocation

<lang vb> dim flat set flat = new flattener flat.itemSeparator = "~" wscript.echo join( flat.flatten( array( array( 1 ),2,array(array(3,4),5),array(array(array())),array(array(array(6))),7,8,array())), "!") </lang>

Output

<lang vb> 1!2!3!4!5!6!7!8 </lang>