From f2087df1cc54537608bea13608f52c60c153e066 Mon Sep 17 00:00:00 2001 From: Jeff Tratner Date: Mon, 17 Nov 2014 12:47:10 -0800 Subject: [PATCH 1/3] BUG: Implement step in slice StringMethod Resolves #8754. --- doc/source/whatsnew/v0.15.2.txt | 1 + pandas/core/strings.py | 3 ++- pandas/tests/test_strings.py | 20 ++++++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.15.2.txt b/doc/source/whatsnew/v0.15.2.txt index c85a9376fc93f..f8b20eaace50e 100644 --- a/doc/source/whatsnew/v0.15.2.txt +++ b/doc/source/whatsnew/v0.15.2.txt @@ -69,6 +69,7 @@ Bug Fixes - ``io.data.Options`` now raises ``RemoteDataError`` when no expiry dates are available from Yahoo (:issue:`8761`). - ``Timedelta`` kwargs may now be numpy ints and floats (:issue:`8757`). - ``sql_schema`` now generates dialect appropriate ``CREATE TABLE`` statements (:issue:`8697`) +- ``slice`` string method now takes step into account (:issue:`8754`) diff --git a/pandas/core/strings.py b/pandas/core/strings.py index 78780bc9618f7..563f5c16fb1e4 100644 --- a/pandas/core/strings.py +++ b/pandas/core/strings.py @@ -674,6 +674,7 @@ def str_slice(arr, start=None, stop=None, step=1): ---------- start : int or None stop : int or None + step : int or None Returns ------- @@ -994,7 +995,7 @@ def center(self, width): @copy(str_slice) def slice(self, start=None, stop=None, step=1): - result = str_slice(self.series, start, stop) + result = str_slice(self.series, start, stop, step) return self._wrap_result(result) @copy(str_slice) diff --git a/pandas/tests/test_strings.py b/pandas/tests/test_strings.py index 02808ebf0b340..2369bd8d572cb 100644 --- a/pandas/tests/test_strings.py +++ b/pandas/tests/test_strings.py @@ -628,6 +628,7 @@ def test_empty_str_methods(self): tm.assert_series_equal(empty_str, empty.str.center(42)) tm.assert_series_equal(empty_list, empty.str.split('a')) tm.assert_series_equal(empty_str, empty.str.slice(stop=1)) + tm.assert_series_equal(empty_str, empty.str.slice(step=1)) tm.assert_series_equal(empty_str, empty.str.strip()) tm.assert_series_equal(empty_str, empty.str.lstrip()) tm.assert_series_equal(empty_str, empty.str.rstrip()) @@ -922,6 +923,17 @@ def test_slice(self): exp = Series(['foo', 'bar', NA, 'baz']) tm.assert_series_equal(result, exp) + for start, stop, step in [(0, 3, -1), (None, None, -1), + (3, 10, 2), (3, 0, -1)]: + try: + result = values.str.slice(start, stop, step) + expected = Series([s[start:stop:step] if not isnull(s) else NA for s in + values]) + tm.assert_series_equal(result, expected) + except: + print('failed on %s:%s:%s' % (start, stop, step)) + raise + # mixed mixed = Series(['aafootwo', NA, 'aabartwo', True, datetime.today(), None, 1, 2.]) @@ -933,6 +945,10 @@ def test_slice(self): tm.assert_isinstance(rs, Series) tm.assert_almost_equal(rs, xp) + rs = Series(mixed).str.slice(2, 5, -1) + xp = Series(['oof', NA, 'rab', NA, NA, + NA, NA, NA]) + # unicode values = Series([u('aafootwo'), u('aabartwo'), NA, u('aabazqux')]) @@ -941,6 +957,10 @@ def test_slice(self): exp = Series([u('foo'), u('bar'), NA, u('baz')]) tm.assert_series_equal(result, exp) + result = values.str.slice(0, -1, 2) + exp = Series([u('afow'), u('abrw'), NA, u('abzu')]) + tm.assert_series_equal(result, exp) + def test_slice_replace(self): pass From 4471700e0201fd1bfd72f2e306a3a5054f16bf3e Mon Sep 17 00:00:00 2001 From: Jeff Tratner Date: Mon, 17 Nov 2014 12:50:51 -0800 Subject: [PATCH 2/3] Add test for __getitem__ syntax on str --- pandas/tests/test_strings.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pandas/tests/test_strings.py b/pandas/tests/test_strings.py index 2369bd8d572cb..a7d3c53c31e3d 100644 --- a/pandas/tests/test_strings.py +++ b/pandas/tests/test_strings.py @@ -1171,6 +1171,10 @@ def test_string_slice_get_syntax(self): expected = s.str.slice(stop=3) assert_series_equal(result, expected) + result = s.str[2::-1] + expected = s.str.slice(start=2, step=-1) + assert_series_equal(result, expected) + def test_string_slice_out_of_bounds(self): s = Series([(1, 2), (1,), (3,4,5)]) From 14199f5b909c3939e611174439096206ca54afbe Mon Sep 17 00:00:00 2001 From: Jeff Tratner Date: Mon, 17 Nov 2014 16:12:36 -0800 Subject: [PATCH 3/3] Make step None (same as 1) for consistency --- pandas/core/strings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/core/strings.py b/pandas/core/strings.py index 563f5c16fb1e4..2c2a98c0c5434 100644 --- a/pandas/core/strings.py +++ b/pandas/core/strings.py @@ -666,7 +666,7 @@ def str_split(arr, pat=None, n=None, return_type='series'): return res -def str_slice(arr, start=None, stop=None, step=1): +def str_slice(arr, start=None, stop=None, step=None): """ Slice substrings from each element in array @@ -994,7 +994,7 @@ def center(self, width): return self._wrap_result(result) @copy(str_slice) - def slice(self, start=None, stop=None, step=1): + def slice(self, start=None, stop=None, step=None): result = str_slice(self.series, start, stop, step) return self._wrap_result(result)