Skip to content
SelectricSimian edited this page Feb 21, 2013 · 1 revision

This function "flattens" a table, removing all nesting structure. For example,

flatten {
  1
  2
  {
    {
      3
      4
    }
    5
  }
  {
    {
      6
    }
    {
      {
        7
      }
    }
  }
}

returns

{
  1
  2
  3
  4
  5
  6
  7
}

Implementation

_insert_many = (...)=> for val in *{...} do self[#self + 1] = val

_flatten = =>
    switch type self
        when 'table'
            result = {}
            for v in *self do _insert_many result, _flatten v
            unpack result
        else
            self

export flatten = (...)-> {_flatten ...}

Non-destructivity

flatten returns a copy of the table parameter, and is guaranteed not to modify its input.

Handling of non-integer keys

For the sake of efficiency and simplicity, flatten completely ignores all non-integer keys. For example,

flatten {
  1
  {2}
  {
    a: 'b'
    c: 'd'
    {
      3
      {4}
    }
  }
  {
    5
    {6}
  }
}

returns

{
  1
  2
  3
  4
  5
  6
}

For tasks which require the data held in, for example, string keys, different approaches may be used. Under certain circumstances, one may want not to flatten any non-sequence table, or any of its sub-tables:

_insert_many = (...)=> for val in *{...} do self[#self + 1] = val

-- moon.fold doesn't quite seem to work...
fold = nil
do
  _fold = (fn, a, b, ...)-> if b then _fold fn, fn(a, b), ... else a
  fold = (fn)=> _fold fn, unpack self

_flatten_direct_sequences = =>
    switch type self
        when 'table'
            if #self == moon.fold [1 for k in pairs self], (a, b)-> a + b
                result = {}
                for v in *self do _insert_many result, _flatten v
                unpack result
            else
                self
        else
            self

export flatten_direct_sequences = (...)-> {_flatten_direct_sequences ...}

example:

flatten_direct_sequences {
  1
  {2}
  {
    a: 'b'
    c: 'd'
    {
      3
      {4}
    }
  }
  {
    5
    {6}
  }
}

returns

{
  1
  2
  {
    a: 'b'
    c: 'd'
    {
      3
      {4}
    }
  }
  5
  6
}

Other times, it may be desirable not to flatten non-sequence tables, but to flatten all sub-tables of those tables:

_insert_many = (...)=> for val in *{...} do self[#self + 1] = val

-- moon.fold doesn't quite seem to work...
fold = nil
do
  _fold = (fn, a, b, ...)-> if b then _fold fn, fn(a, b), ... else a
  fold = (fn)=> _fold fn, unpack self

_flatten_all_sequences = =>
    switch type self
        when 'table'
            if #self == moon.fold [1 for k in pairs self], (a, b)-> a + b
                result = {}
                for v in *self do _insert_many result, _flatten v
                unpack result
            else
                {k, flatten_all_sequences v for k, v in pairs self}
        else
            self

export flatten_all_sequences = (...)-> {_flatten_all_sequences ...}

example:

flatten_all_sequences {
  1
  {2}
  {
    a: 'b'
    c: 'd'
    {
      3
      {4}
    }
  }
  {
    5
    {6}
  }
}

returns

{
  1
  2
  {
    a: 'b'
    c: 'd'
    {
      3
      4
    }
  }
  5
  6
}