Skip to content

Commit

Permalink
Merge pull request #20 from tacaswell/enh_concat
Browse files Browse the repository at this point in the history
ENH: add concat
  • Loading branch information
efiring committed Oct 12, 2015
2 parents 1f3e5c4 + 495d0f4 commit a1d60c7
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 4 deletions.
3 changes: 1 addition & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ language: python

matrix:
include:
- python: 2.6
- python: 2.7
- python: 3.3
- python: 3.4
- python: 3.5
- python: "nightly"
env: PRE=--pre
allow_failures:
Expand Down
68 changes: 68 additions & 0 deletions cycler.py
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,74 @@ def simplify(self):
trans = self._transpose()
return reduce(add, (_cycler(k, v) for k, v in six.iteritems(trans)))

def concat(self, other):
"""Concatenate this cycler and an other.
The keys must match exactly.
This returns a single Cycler which is equivalent to
`itertools.chain(self, other)`
Examples
--------
>>> num = cycler('a', range(3))
>>> let = cycler('a', 'abc')
>>> num.concat(let)
cycler('a', [0, 1, 2, 'a', 'b', 'c'])
Parameters
----------
other : `Cycler`
The `Cycler` to concatenate to this one.
Returns
-------
ret : `Cycler`
The concatenated `Cycler`
"""
return concat(self, other)


def concat(left, right):
"""Concatenate two cyclers.
The keys must match exactly.
This returns a single Cycler which is equivalent to
`itertools.chain(left, right)`
Examples
--------
>>> num = cycler('a', range(3))
>>> let = cycler('a', 'abc')
>>> num.concat(let)
cycler('a', [0, 1, 2, 'a', 'b', 'c'])
Parameters
----------
left, right : `Cycler`
The two `Cycler` instances to concatenate
Returns
-------
ret : `Cycler`
The concatenated `Cycler`
"""
if left.keys != right.keys:
msg = '\n\t'.join(["Keys do not match:",
"Intersection: {both!r}",
"Disjoint: {just_one!r}"
]).format(
both=left.keys&right.keys,
just_one=left.keys^right.keys)

raise ValueError(msg)

_l = left._transpose()
_r = right._transpose()
return reduce(add, (_cycler(k, _l[k] + _r[k]) for k in left.keys))

def cycler(*args, **kwargs):
"""
Expand Down
16 changes: 16 additions & 0 deletions doc/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,22 @@ Integer Multiplication
2 * color_cycle
Concatenation
~~~~~~~~~~~~~

`Cycler` objects can be concatenated either via the :py:meth:`Cycler.concat` method

.. ipython:: python
color_cycle.concat(color_cycle)
or the top-level :py:func:`concat` function

.. ipython:: python
from cycler import concat
concat(color_cycle, color_cycle)
Slicing
-------
Expand Down
21 changes: 19 additions & 2 deletions test_cycler.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

import six
from six.moves import zip, range
from cycler import cycler, Cycler
from cycler import cycler, Cycler, concat
from nose.tools import (assert_equal, assert_not_equal,
assert_raises, assert_true)
from itertools import product, cycle
from itertools import product, cycle, chain
from operator import add, iadd, mul, imul


Expand Down Expand Up @@ -279,3 +279,20 @@ def test_starange_init():
c2 = cycler('lw', range(3))
cy = Cycler(list(c), list(c2), zip)
assert_equal(cy, c + c2)


def test_concat():
a = cycler('a', range(3))
b = cycler('a', 'abc')
for con, chn in zip(a.concat(b), chain(a, b)):
assert_equal(con, chn)

for con, chn in zip(concat(a, b), chain(a, b)):
assert_equal(con, chn)


def test_concat_fail():
a = cycler('a', range(3))
b = cycler('b', range(3))
assert_raises(ValueError, concat, a, b)
assert_raises(ValueError, a.concat, b)

0 comments on commit a1d60c7

Please sign in to comment.