Skip to content

Commit ef019fa

Browse files
h-vetinarijreback
authored andcommitted
Follow-up #20347: incorporate review about _get_series_list (#20923)
1 parent ec4609e commit ef019fa

File tree

3 files changed

+42
-39
lines changed

3 files changed

+42
-39
lines changed

doc/source/text.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ All one-dimensional list-likes can be arbitrarily combined in a list-like contai
311311
312312
s
313313
u
314-
s.str.cat([u, pd.Index(u.values), ['A', 'B', 'C', 'D'], map(int, u.index)], na_rep='-')
314+
s.str.cat([u, pd.Index(u.values), ['A', 'B', 'C', 'D'], map(str, u.index)], na_rep='-')
315315
316316
All elements must match in length to the calling ``Series`` (or ``Index``), except those having an index if ``join`` is not None:
317317

doc/source/whatsnew/v0.23.0.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ The :func:`DataFrame.assign` now accepts dependent keyword arguments for python
314314
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
315315

316316
Previously, :meth:`Series.str.cat` did not -- in contrast to most of ``pandas`` -- align :class:`Series` on their index before concatenation (see :issue:`18657`).
317-
The method has now gained a keyword ``join`` to control the manner of alignment, see examples below and in :ref:`here <text.concatenate>`.
317+
The method has now gained a keyword ``join`` to control the manner of alignment, see examples below and :ref:`here <text.concatenate>`.
318318

319319
In v.0.23 `join` will default to None (meaning no alignment), but this default will change to ``'left'`` in a future version of pandas.
320320

@@ -325,7 +325,7 @@ In v.0.23 `join` will default to None (meaning no alignment), but this default w
325325
s.str.cat(t)
326326
s.str.cat(t, join='left', na_rep='-')
327327

328-
Furthermore, meth:`Series.str.cat` now works for ``CategoricalIndex`` as well (previously raised a ``ValueError``; see :issue:`20842`).
328+
Furthermore, :meth:`Series.str.cat` now works for ``CategoricalIndex`` as well (previously raised a ``ValueError``; see :issue:`20842`).
329329

330330
.. _whatsnew_0230.enhancements.astype_category:
331331

pandas/core/strings.py

+39-36
Original file line numberDiff line numberDiff line change
@@ -1943,21 +1943,21 @@ def _get_series_list(self, others, ignore_index=False):
19431943
19441944
Parameters
19451945
----------
1946-
input : Series, DataFrame, np.ndarray, list-like or list-like of
1946+
others : Series, DataFrame, np.ndarray, list-like or list-like of
19471947
objects that are either Series, np.ndarray (1-dim) or list-like
19481948
ignore_index : boolean, default False
1949-
Determines whether to forcefully align with index of the caller
1949+
Determines whether to forcefully align others with index of caller
19501950
19511951
Returns
19521952
-------
1953-
tuple : (input transformed into list of Series,
1954-
Boolean whether FutureWarning should be raised)
1953+
tuple : (others transformed into list of Series,
1954+
boolean whether FutureWarning should be raised)
19551955
"""
19561956

19571957
# once str.cat defaults to alignment, this function can be simplified;
19581958
# will not need `ignore_index` and the second boolean output anymore
19591959

1960-
from pandas import Index, Series, DataFrame, isnull
1960+
from pandas import Index, Series, DataFrame
19611961

19621962
# self._orig is either Series or Index
19631963
idx = self._orig if isinstance(self._orig, Index) else self._orig.index
@@ -1966,66 +1966,69 @@ def _get_series_list(self, others, ignore_index=False):
19661966
'list-like (either containing only strings or containing '
19671967
'only objects of type Series/Index/list-like/np.ndarray)')
19681968

1969+
# Generally speaking, all objects without an index inherit the index
1970+
# `idx` of the calling Series/Index - i.e. must have matching length.
1971+
# Objects with an index (i.e. Series/Index/DataFrame) keep their own
1972+
# index, *unless* ignore_index is set to True.
19691973
if isinstance(others, Series):
1970-
fu_wrn = not others.index.equals(idx)
1974+
warn = not others.index.equals(idx)
1975+
# only reconstruct Series when absolutely necessary
19711976
los = [Series(others.values, index=idx)
1972-
if ignore_index and fu_wrn else others]
1973-
return (los, fu_wrn)
1977+
if ignore_index and warn else others]
1978+
return (los, warn)
19741979
elif isinstance(others, Index):
1975-
fu_wrn = not others.equals(idx)
1980+
warn = not others.equals(idx)
19761981
los = [Series(others.values,
19771982
index=(idx if ignore_index else others))]
1978-
return (los, fu_wrn)
1983+
return (los, warn)
19791984
elif isinstance(others, DataFrame):
1980-
fu_wrn = not others.index.equals(idx)
1981-
if ignore_index and fu_wrn:
1985+
warn = not others.index.equals(idx)
1986+
if ignore_index and warn:
19821987
# without copy, this could change "others"
19831988
# that was passed to str.cat
19841989
others = others.copy()
19851990
others.index = idx
1986-
return ([others[x] for x in others], fu_wrn)
1991+
return ([others[x] for x in others], warn)
19871992
elif isinstance(others, np.ndarray) and others.ndim == 2:
19881993
others = DataFrame(others, index=idx)
19891994
return ([others[x] for x in others], False)
19901995
elif is_list_like(others):
19911996
others = list(others) # ensure iterators do not get read twice etc
1997+
1998+
# in case of list-like `others`, all elements must be
1999+
# either one-dimensional list-likes or scalars
19922000
if all(is_list_like(x) for x in others):
19932001
los = []
1994-
fu_wrn = False
2002+
warn = False
2003+
# iterate through list and append list of series for each
2004+
# element (which we check to be one-dimensional and non-nested)
19952005
while others:
1996-
nxt = others.pop(0) # list-like as per check above
1997-
# safety for iterators and other non-persistent list-likes
1998-
# do not map indexed/typed objects; would lose information
2006+
nxt = others.pop(0) # nxt is guaranteed list-like by above
19992007
if not isinstance(nxt, (DataFrame, Series,
20002008
Index, np.ndarray)):
2009+
# safety for non-persistent list-likes (e.g. iterators)
2010+
# do not map indexed/typed objects; info needed below
20012011
nxt = list(nxt)
20022012

2003-
# known types without deep inspection
2013+
# known types for which we can avoid deep inspection
20042014
no_deep = ((isinstance(nxt, np.ndarray) and nxt.ndim == 1)
20052015
or isinstance(nxt, (Series, Index)))
2006-
# Nested list-likes are forbidden - elements of nxt must be
2007-
# strings/NaN/None. Need to robustify NaN-check against
2008-
# x in nxt being list-like (otherwise ambiguous boolean)
2016+
# nested list-likes are forbidden:
2017+
# -> elements of nxt must not be list-like
20092018
is_legal = ((no_deep and nxt.dtype == object)
2010-
or all((isinstance(x, compat.string_types)
2011-
or (not is_list_like(x) and isnull(x))
2012-
or x is None)
2013-
for x in nxt))
2019+
or all(not is_list_like(x) for x in nxt))
2020+
20142021
# DataFrame is false positive of is_legal
20152022
# because "x in df" returns column names
20162023
if not is_legal or isinstance(nxt, DataFrame):
20172024
raise TypeError(err_msg)
20182025

2019-
nxt, fwn = self._get_series_list(nxt,
2026+
nxt, wnx = self._get_series_list(nxt,
20202027
ignore_index=ignore_index)
20212028
los = los + nxt
2022-
fu_wrn = fu_wrn or fwn
2023-
return (los, fu_wrn)
2024-
# test if there is a mix of list-like and non-list-like (e.g. str)
2025-
elif (any(is_list_like(x) for x in others)
2026-
and any(not is_list_like(x) for x in others)):
2027-
raise TypeError(err_msg)
2028-
else: # all elements in others are _not_ list-like
2029+
warn = warn or wnx
2030+
return (los, warn)
2031+
elif all(not is_list_like(x) for x in others):
20292032
return ([Series(others, index=idx)], False)
20302033
raise TypeError(err_msg)
20312034

@@ -2187,8 +2190,8 @@ def cat(self, others=None, sep=None, na_rep=None, join=None):
21872190

21882191
try:
21892192
# turn anything in "others" into lists of Series
2190-
others, fu_wrn = self._get_series_list(others,
2191-
ignore_index=(join is None))
2193+
others, warn = self._get_series_list(others,
2194+
ignore_index=(join is None))
21922195
except ValueError: # do not catch TypeError raised by _get_series_list
21932196
if join is None:
21942197
raise ValueError('All arrays must be same length, except '
@@ -2199,7 +2202,7 @@ def cat(self, others=None, sep=None, na_rep=None, join=None):
21992202
'must all be of the same length as the '
22002203
'calling Series/Index.')
22012204

2202-
if join is None and fu_wrn:
2205+
if join is None and warn:
22032206
warnings.warn("A future version of pandas will perform index "
22042207
"alignment when `others` is a Series/Index/"
22052208
"DataFrame (or a list-like containing one). To "

0 commit comments

Comments
 (0)