DEPR: list-likes of list-likes in str.cat
State: closed

- [x] closes #21950
- [x] tests modified / passed
- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [x] whatsnew entry

As mentioned in #21950, my suggestion is to modify the allowed combinations (as of v0.23) as follows:
```
Type of "others"                        |  action  |  comment
---------------------------------------------------------------------
list-like of strings                    |   keep   |  as before; mimics behavior elsewhere,
                                                      cf.: pd.Series(range(3)) + [2,4,6]
Series                                  |   keep   |
np.ndarray (1-dim)                      |   keep   |
DataFrame                               |   keep   |  sequential concatenation
np.ndarray (2-dim)                      |   keep   |  sequential concatenation
list-like of
    Series/Index/np.ndarray (1-dim)     |   keep   |  sequential concatenation
list-like containing list-likes (1-dim)
    other than Series/Index/np.ndarray  |   DEPR   |  sequential concatenation
```

In other words, if the user wants sequential concatenation, there are many possibilities available, and list-of-lists does not have to be one of them, IMO. This would substantially simplify (post-deprecation) the code for `str.cat._get_series_list`: 


```
def _get_series_list(self, others):
    """
    Auxiliary function for :meth:`str.cat`. Turn potentially mixed input
    into a list of Series (elements without an index must match the length
    of the calling Series/Index).

    Parameters
    ----------
    others : Series, DataFrame, np.ndarray, list-like or list-like of
        objects that are either Series, Index or np.ndarray (1-dim)

    Returns
    -------
    list : others transformed into list of Series
    """
    from pandas import Index, Series, DataFrame

    # self._orig is either Series or Index
    idx = self._orig if isinstance(self._orig, Index) else self._orig.index

    # Generally speaking, all objects without an index inherit the index
    # `idx` of the calling Series/Index - i.e. must have matching length.
    # Objects with an index (i.e. Series/Index/DataFrame) keep their own.
    if isinstance(others, Series):
        return [others]
    elif isinstance(others, Index):
        return [Series(others.values, index=others)]
    elif isinstance(others, DataFrame):
        return [others[x] for x in others]
    elif isinstance(others, np.ndarray) and others.ndim == 2:
        others = DataFrame(others, index=idx)
        return [others[x] for x in others]
    elif is_list_like(others):
        others = list(others)  # ensure iterators do not get read twice etc

        # in case of list-like `others`, all elements must be
        # either Series/Index/np.ndarray (1-dim)...
        if all(isinstance(x, (Series, Index))
               or (isinstance(x, np.ndarray) and x.ndim == 1) for x in others):
            los = []
            while others:  # iterate through list and append each element
                los = los + self._get_series_list(others.pop(0))
            return los
        # ... or just strings
        elif all(not is_list_like(x) for x in others):
            return [Series(others, index=idx)]
    raise TypeError('others must be Series, Index, DataFrame, np.ndarrary or '
                    'list-like (either containing only strings or containing '
                    'only objects of type Series/Index/np.ndarray[1-dim])')
```


Labels:
name: Strings
description: String extension data type and string data
name: Deprecate
description: Functionality to remove in pandas

Comments:
Hello @h-vetinari! Thanks for updating the PR.





Cheers ! There are no PEP8 issues in this Pull Request. :beers: 

##### Comment last updated on August 28, 2018 at 17:09 Hours UTC
# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/22264?src=pr&el=h1) Report
> :exclamation: No coverage uploaded for pull request base (`master@fa47b8d`). [Click here to learn what that means](https://docs.codecov.io/docs/error-reference#section-missing-base-commit).
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/pandas-dev/pandas/pull/22264/graphs/tree.svg?width=650&token=eZ4WkYLtcO&height=150&src=pr)](https://codecov.io/gh/pandas-dev/pandas/pull/22264?src=pr&el=tree)

```diff
@@            Coverage Diff            @@
##             master   #22264   +/-   ##
=========================================
  Coverage          ?   92.03%           
=========================================
  Files             ?      169           
  Lines             ?    50785           
  Branches          ?        0           
=========================================
  Hits              ?    46742           
  Misses            ?     4043           
  Partials          ?        0
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `90.44% <100%> (?)` | |
| #single | `42.22% <0%> (?)` | |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/22264?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/core/strings.py](https://codecov.io/gh/pandas-dev/pandas/pull/22264/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvc3RyaW5ncy5weQ==) | `98.63% <100%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/22264?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/22264?src=pr&el=footer). Last update [fa47b8d...7e74d80](https://codecov.io/gh/pandas-dev/pandas/pull/22264?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

maybe would be helpful to show a rendered version here of text.rst
@jreback here you go:

![1](https://user-images.githubusercontent.com/33685575/43965824-944275c6-9cc0-11e8-91b0-183d3a45f13b.png)

@jreback @TomAugspurger ping :)
@jreback Incorporated feedback, except the `u.values` part, where my comment above doesn't show up (so copying it here):

> so pls show u.values, I have no idea what it actually is, and as I said, pls either add comments or split up showing s, u, u.values, this is just too long

`u` is shown directly above...?! Also in the screenshot I posted. I can of course show **both** `u` and `u.values`, but I thought that understanding the relationship between a Series and its `.values` would be safe to expect of a users' pandas-fu.

In context it's IMO very clear (especially as it's at the end of the concatenation section, where the reader has seen the same objects 10 times already).
@jreback Same screenshot as above. IMO the relationship `u` <--> `u.values` does not need to be explained - if you disagree with that, please let me know. (side note: the example in the current docs is even more complicated; but ultimately its easy to grok from the result what's the content of the inputs -- see `[70]` below)

![1_alt](https://user-images.githubusercontent.com/33685575/44383551-5d20db80-a519-11e8-889e-2f87d0ec8452.png)

ok this is fine. can you rebase once more and ping on green.
@jreback All green.
@jreback 
> ok this is fine. can you rebase once more and ping on green.

All green. Just fixed an indentation error on the way.
@jreback 
> tiny typo, ping on push.

Side note: `[ci skip]` does not seem to be respected by the new CircleCI.
@jreback

This is all done, approved and green.
> Side note: [ci skip] does not seem to be respected by the new CircleCI.

I don't like these skip's generally. they are not necessary as all of the CI's cancel prior builds anyhow.
thanks @h-vetinari 
@jreback 

> > Side note: [ci skip] does not seem to be respected by the new CircleCI.

> I don't like these skip's generally. they are not necessary as all of the CI's cancel prior builds anyhow.

This was not about cancelling prior builds but not having to run the full CI suite if (say) a single comment (like for the GH number) gets added. I view the CI as somewhat limited resources (appveyor recently having something like 12h waiting time), so `[ci skip]` can be useful for avoiding a CI run where it's pointless (any code/doc changes should of course run through).