BUG: list-like to_replace on Categorical.replace is ignored or crash
- [X] closes #31720
- [X] tests added / passed
- [x] passes `black pandas`
- [X] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [X] whatsnew entry

Covers the case where `to_replace` is a list-like and `value` is a string. Other cases, like "`to_replace` is dict and `value` is None", or "`to_replace` and `value` are both lists" are handled earlier in generic.py
How does this behave when `to_replace` is already a dict? On master the replacement seems to work but the data type changes:

```python
In [5]: s                                                                                                                                                             
Out[5]: 
0    0
1    1
2    2
dtype: category
Categories (3, int64): [0, 1, 2]

In [6]: s.replace({0: 1})                                                                                                                                             
Out[6]: 
0    1
1    1
2    2
dtype: int64
``` @dsaxton this is because in `NDFrame` (generics.py) it chooses to not dispatch the dict case to the `self._data.replace`, but `self._data.replace_list` which takes a more complex path to iterate over its blocks and would need more drastic refactoring (it pre-computes masks to avoid repeated replacement if the same value appears more than once in `to_replace` or `value`). I think that is outside the scope of the current ticket Thanks @JustinZhengBC ! 

Overall looks good Hello @JustinZhengBC! Thanks for updating this PR. We checked the lines you've touched for [PEP 8](https://www.python.org/dev/peps/pep-0008) issues, and found:







There are currently no PEP 8 issues detected in this Pull Request. Cheers! :beers: 

##### Comment last updated at 2020-02-17 00:22:52 UTC @jreback I've moved the whatsnew and addressed the other feedback also pls merge master @jreback green thanks @JustinZhengBC very nice!