De-duplicate code for indexing with list-likes of keys
State: closed

- [x] tests passed
- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`

Just refactoring, removing duplicated code (I don't think the bug in ``Index._reindex_non_unique`` was actually appearing anywhere)

Labels:
name: Refactor
description: Internal refactoring of code
name: Indexing
description: Related to indexing on series/frames, not to indexes themselves
name: Clean

Comments:
(there is still room for improvement, by the way, but I will need to look in the ``Index`` methods)
# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/21503?src=pr&el=h1) Report
> Merging [#21503](https://codecov.io/gh/pandas-dev/pandas/pull/21503?src=pr&el=desc) into [master](https://codecov.io/gh/pandas-dev/pandas/commit/71c53f0be9b49af0fdf5c6965b2a5a217b9f7179?src=pr&el=desc) will **decrease** coverage by `<.01%`.
> The diff coverage is `100%`.

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

```diff
@@            Coverage Diff             @@
##           master   #21503      +/-   ##
==========================================
- Coverage   91.92%   91.92%   -0.01%     
==========================================
  Files         153      153              
  Lines       49594    49570      -24     
==========================================
- Hits        45590    45566      -24     
  Misses       4004     4004
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `90.32% <100%> (-0.01%)` | :arrow_down: |
| #single | `41.82% <80.64%> (-0.01%)` | :arrow_down: |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/21503?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/core/indexing.py](https://codecov.io/gh/pandas-dev/pandas/pull/21503/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvaW5kZXhpbmcucHk=) | `93.41% <100%> (-0.15%)` | :arrow_down: |
| [pandas/core/frame.py](https://codecov.io/gh/pandas-dev/pandas/pull/21503/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZnJhbWUucHk=) | `97.23% <100%> (ø)` | :arrow_up: |
| [pandas/core/indexes/base.py](https://codecov.io/gh/pandas-dev/pandas/pull/21503/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvaW5kZXhlcy9iYXNlLnB5) | `96.62% <100%> (ø)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/21503?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/21503?src=pr&el=footer). Last update [71c53f0...2b07ab0](https://codecov.io/gh/pandas-dev/pandas/pull/21503?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

ASV run (of ``indexing.py``):

```
       before           after         ratio
     [9e982e18]       [c08a39fa]
+       146±0.7ms        167±0.7ms     1.14  frame_methods.Iteration.time_iteritems_indexing
-         103±2μs         93.2±2μs     0.91  indexing.DataFrameNumericIndexing.time_loc
-         213±2μs          193±1μs     0.91  indexing.DataFrameNumericIndexing.time_iloc_dups
-         250±2μs          224±1μs     0.90  indexing.DataFrameStringIndexing.time_boolean_rows
-         162±1μs          144±1μs     0.89  indexing.IntervalIndexing.time_getitem_list
-      53.1±0.2μs       46.3±0.3μs     0.87  indexing.IntervalIndexing.time_getitem_scalar
-     2.33±0.01ms      2.00±0.02ms     0.86  indexing.DataFrameNumericIndexing.time_loc_dups
-         494±8ns          424±5ns     0.86  indexing.MethodLookup.time_lookup_iloc
-         727±4μs         623±10μs     0.86  indexing.NumericSeriesIndexing.time_loc_list_like(<class 'pandas.core.indexes.numeric.Int64Index'>)
-        88.6±2μs       74.9±0.6μs     0.85  indexing.IntervalIndexing.time_loc_scalar
-     1.67±0.07ms      1.34±0.02ms     0.80  indexing.NumericSeriesIndexing.time_loc_array(<class 'pandas.core.indexes.numeric.Int64Index'>)
-     1.90±0.09ms      1.44±0.01ms     0.76  indexing.NumericSeriesIndexing.time_getitem_array(<class 'pandas.core.indexes.numeric.Int64Index'>)
-     1.77±0.07ms      1.30±0.01ms     0.73  indexing.NumericSeriesIndexing.time_ix_array(<class 'pandas.core.indexes.numeric.Int64Index'>)
-         799±8μs          519±4μs     0.65  indexing.NumericSeriesIndexing.time_ix_list_like(<class 'pandas.core.indexes.numeric.Int64Index'>)
-         319±5ms          201±4ms     0.63  indexing.NumericSeriesIndexing.time_ix_array(<class 'pandas.core.indexes.numeric.Float64Index'>)
-       307±0.9ms          185±2ms     0.60  indexing.NumericSeriesIndexing.time_ix_list_like(<class 'pandas.core.indexes.numeric.Float64Index'>)

SOME BENCHMARKS HAVE CHANGED SIGNIFICANTLY.
```
@jreback @jorisvandenbossche ping
> assumed this to make some other of your PRs simpler if this is a precursor?

Not sure I understand. This transforms three copies of the same code into one (and in doing so removes some superfluous calls, explaining the performance improvements). So yes, incidentally it will also make it easier to further rationalize the indexing code, and yes, I plan to work on it.
@toobaz no that's what I was asking. thanks.
@jreback ping
very nice @toobaz 

more like this very welcome!