<h4 dir="auto">Code Sample, a copy-pastable example if possible</h4>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import pandas as pd


class KV(object):

  def __init__(self, key, val):
    self.key = key
    self.val = val

  def __str__(self):
    return 'KV({!r}:{!r})'.format(self.key, self.val)

  def __hash__(self):
    return hash(self.key)

  def __eq__(self, other):
    if isinstance(other, basestring):
      return self.key == other
    elif isinstance(other, KV):
      return self.key == other.key and self.val == other.val
    return NotImplemented

  def __ne__(self, other):
    equals = self == other
    if equals is NotImplemented:
      return NotImplemented
    return not equals

  def __lt__(self, other):
    if isinstance(other, basestring):
      return self.key &lt; other
    return NotImplemented

  def __le__(self, other):
    if isinstance(other, basestring):
      return self.key &lt;= other
    return NotImplemented

  def __gt__(self, other):
    if isinstance(other, basestring):
      return self.key &gt; other
    return NotImplemented

  def __ge__(self, other):
    if isinstance(other, basestring):
      return self.key &gt;= other
    return NotImplemented


# labels with transitive equality
idx = pd.Index(['a', 'a'])

assert idx.get_loc('a') == slice(0, 2) # string selects both values
assert (idx == 'a').tolist() == [True, True]  # string selects both values

# labels with non-transitive equality
a1 = KV('a', 1)
a2 = KV('a', 2)

assert a1 == 'a' # KV and string match on key
assert a2 == 'a' # KV and string match on key
assert a1 != a2 # KV and KV match on key, but not on value

idx = pd.Index([a1, a2])

assert idx.get_loc('a') == 0 # string selects first KV
assert (idx == 'a').tolist() == [True, True]  # string selects both KVs"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-s1">pandas</span> <span class="pl-k">as</span> <span class="pl-s1">pd</span>


<span class="pl-k">class</span> <span class="pl-v">KV</span>(<span class="pl-s1">object</span>):

  <span class="pl-k">def</span> <span class="pl-en">__init__</span>(<span class="pl-s1">self</span>, <span class="pl-s1">key</span>, <span class="pl-s1">val</span>):
    <span class="pl-s1">self</span>.<span class="pl-s1">key</span> <span class="pl-c1">=</span> <span class="pl-s1">key</span>
    <span class="pl-s1">self</span>.<span class="pl-s1">val</span> <span class="pl-c1">=</span> <span class="pl-s1">val</span>

  <span class="pl-k">def</span> <span class="pl-en">__str__</span>(<span class="pl-s1">self</span>):
    <span class="pl-k">return</span> <span class="pl-s">'KV({!r}:{!r})'</span>.<span class="pl-en">format</span>(<span class="pl-s1">self</span>.<span class="pl-s1">key</span>, <span class="pl-s1">self</span>.<span class="pl-s1">val</span>)

  <span class="pl-k">def</span> <span class="pl-en">__hash__</span>(<span class="pl-s1">self</span>):
    <span class="pl-k">return</span> <span class="pl-en">hash</span>(<span class="pl-s1">self</span>.<span class="pl-s1">key</span>)

  <span class="pl-k">def</span> <span class="pl-en">__eq__</span>(<span class="pl-s1">self</span>, <span class="pl-s1">other</span>):
    <span class="pl-k">if</span> <span class="pl-en">isinstance</span>(<span class="pl-s1">other</span>, <span class="pl-s1">basestring</span>):
      <span class="pl-k">return</span> <span class="pl-s1">self</span>.<span class="pl-s1">key</span> <span class="pl-c1">==</span> <span class="pl-s1">other</span>
    <span class="pl-k">elif</span> <span class="pl-en">isinstance</span>(<span class="pl-s1">other</span>, <span class="pl-v">KV</span>):
      <span class="pl-k">return</span> <span class="pl-s1">self</span>.<span class="pl-s1">key</span> <span class="pl-c1">==</span> <span class="pl-s1">other</span>.<span class="pl-s1">key</span> <span class="pl-c1">and</span> <span class="pl-s1">self</span>.<span class="pl-s1">val</span> <span class="pl-c1">==</span> <span class="pl-s1">other</span>.<span class="pl-s1">val</span>
    <span class="pl-k">return</span> <span class="pl-v">NotImplemented</span>

  <span class="pl-k">def</span> <span class="pl-en">__ne__</span>(<span class="pl-s1">self</span>, <span class="pl-s1">other</span>):
    <span class="pl-s1">equals</span> <span class="pl-c1">=</span> <span class="pl-s1">self</span> <span class="pl-c1">==</span> <span class="pl-s1">other</span>
    <span class="pl-k">if</span> <span class="pl-s1">equals</span> <span class="pl-c1">is</span> <span class="pl-v">NotImplemented</span>:
      <span class="pl-k">return</span> <span class="pl-v">NotImplemented</span>
    <span class="pl-k">return</span> <span class="pl-c1">not</span> <span class="pl-s1">equals</span>

  <span class="pl-k">def</span> <span class="pl-en">__lt__</span>(<span class="pl-s1">self</span>, <span class="pl-s1">other</span>):
    <span class="pl-k">if</span> <span class="pl-en">isinstance</span>(<span class="pl-s1">other</span>, <span class="pl-s1">basestring</span>):
      <span class="pl-k">return</span> <span class="pl-s1">self</span>.<span class="pl-s1">key</span> <span class="pl-c1">&lt;</span> <span class="pl-s1">other</span>
    <span class="pl-k">return</span> <span class="pl-v">NotImplemented</span>

  <span class="pl-k">def</span> <span class="pl-en">__le__</span>(<span class="pl-s1">self</span>, <span class="pl-s1">other</span>):
    <span class="pl-k">if</span> <span class="pl-en">isinstance</span>(<span class="pl-s1">other</span>, <span class="pl-s1">basestring</span>):
      <span class="pl-k">return</span> <span class="pl-s1">self</span>.<span class="pl-s1">key</span> <span class="pl-c1">&lt;=</span> <span class="pl-s1">other</span>
    <span class="pl-k">return</span> <span class="pl-v">NotImplemented</span>

  <span class="pl-k">def</span> <span class="pl-en">__gt__</span>(<span class="pl-s1">self</span>, <span class="pl-s1">other</span>):
    <span class="pl-k">if</span> <span class="pl-en">isinstance</span>(<span class="pl-s1">other</span>, <span class="pl-s1">basestring</span>):
      <span class="pl-k">return</span> <span class="pl-s1">self</span>.<span class="pl-s1">key</span> <span class="pl-c1">&gt;</span> <span class="pl-s1">other</span>
    <span class="pl-k">return</span> <span class="pl-v">NotImplemented</span>

  <span class="pl-k">def</span> <span class="pl-en">__ge__</span>(<span class="pl-s1">self</span>, <span class="pl-s1">other</span>):
    <span class="pl-k">if</span> <span class="pl-en">isinstance</span>(<span class="pl-s1">other</span>, <span class="pl-s1">basestring</span>):
      <span class="pl-k">return</span> <span class="pl-s1">self</span>.<span class="pl-s1">key</span> <span class="pl-c1">&gt;=</span> <span class="pl-s1">other</span>
    <span class="pl-k">return</span> <span class="pl-v">NotImplemented</span>


<span class="pl-c"># labels with transitive equality</span>
<span class="pl-s1">idx</span> <span class="pl-c1">=</span> <span class="pl-s1">pd</span>.<span class="pl-v">Index</span>([<span class="pl-s">'a'</span>, <span class="pl-s">'a'</span>])

<span class="pl-k">assert</span> <span class="pl-s1">idx</span>.<span class="pl-en">get_loc</span>(<span class="pl-s">'a'</span>) <span class="pl-c1">==</span> <span class="pl-en">slice</span>(<span class="pl-c1">0</span>, <span class="pl-c1">2</span>) <span class="pl-c"># string selects both values</span>
<span class="pl-k">assert</span> (<span class="pl-s1">idx</span> <span class="pl-c1">==</span> <span class="pl-s">'a'</span>).<span class="pl-en">tolist</span>() <span class="pl-c1">==</span> [<span class="pl-c1">True</span>, <span class="pl-c1">True</span>]  <span class="pl-c"># string selects both values</span>

<span class="pl-c"># labels with non-transitive equality</span>
<span class="pl-s1">a1</span> <span class="pl-c1">=</span> <span class="pl-v">KV</span>(<span class="pl-s">'a'</span>, <span class="pl-c1">1</span>)
<span class="pl-s1">a2</span> <span class="pl-c1">=</span> <span class="pl-v">KV</span>(<span class="pl-s">'a'</span>, <span class="pl-c1">2</span>)

<span class="pl-k">assert</span> <span class="pl-s1">a1</span> <span class="pl-c1">==</span> <span class="pl-s">'a'</span> <span class="pl-c"># KV and string match on key</span>
<span class="pl-k">assert</span> <span class="pl-s1">a2</span> <span class="pl-c1">==</span> <span class="pl-s">'a'</span> <span class="pl-c"># KV and string match on key</span>
<span class="pl-k">assert</span> <span class="pl-s1">a1</span> <span class="pl-c1">!=</span> <span class="pl-s1">a2</span> <span class="pl-c"># KV and KV match on key, but not on value</span>

<span class="pl-s1">idx</span> <span class="pl-c1">=</span> <span class="pl-s1">pd</span>.<span class="pl-v">Index</span>([<span class="pl-s1">a1</span>, <span class="pl-s1">a2</span>])

<span class="pl-k">assert</span> <span class="pl-s1">idx</span>.<span class="pl-en">get_loc</span>(<span class="pl-s">'a'</span>) <span class="pl-c1">==</span> <span class="pl-c1">0</span> <span class="pl-c"># string selects first KV</span>
<span class="pl-k">assert</span> (<span class="pl-s1">idx</span> <span class="pl-c1">==</span> <span class="pl-s">'a'</span>).<span class="pl-en">tolist</span>() <span class="pl-c1">==</span> [<span class="pl-c1">True</span>, <span class="pl-c1">True</span>]  <span class="pl-c"># string selects both KVs</span></pre></div>
<h4 dir="auto">Problem description</h4>
<p dir="auto">Selection by labels with non-transitive equality has inconsistent behavior with duplicate labels. I would expect duplicate labels to be selected in all cases.</p>
<h4 dir="auto">Expected Output</h4>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="assert idx.get_loc('a') == slice(0, 2) # string selects both KVs"><pre class="notranslate"><span class="pl-k">assert</span> <span class="pl-s1">idx</span>.<span class="pl-en">get_loc</span>(<span class="pl-s">'a'</span>) <span class="pl-c1">==</span> <span class="pl-en">slice</span>(<span class="pl-c1">0</span>, <span class="pl-c1">2</span>) <span class="pl-c"># string selects both KVs</span></pre></div>
<h4 dir="auto">Output of <code class="notranslate">pd.show_versions()</code></h4>
<details>
<h2 dir="auto">INSTALLED VERSIONS</h2>
<p dir="auto">commit: None<br>
python: 2.7.6.final.0<br>
python-bits: 64<br>
OS: Linux<br>
OS-release: 3.13.0-96-generic<br>
machine: x86_64<br>
processor: x86_64<br>
byteorder: little<br>
LC_ALL: None<br>
LANG: en_US.UTF-8<br>
LOCALE: None.None</p>
<p dir="auto">pandas: 0.20.3<br>
pytest: 3.1.3<br>
pip: 9.0.1<br>
setuptools: 36.2.0<br>
Cython: 0.26<br>
numpy: 1.13.1<br>
scipy: 0.19.1<br>
xarray: None<br>
IPython: 5.4.1<br>
sphinx: 1.6.3<br>
patsy: 0.4.1<br>
dateutil: 2.6.1<br>
pytz: 2017.2<br>
blosc: None<br>
bottleneck: 1.2.1<br>
tables: 3.4.2<br>
numexpr: 2.6.2<br>
feather: None<br>
matplotlib: 2.0.2<br>
openpyxl: None<br>
xlrd: None<br>
xlwt: 0.7.5<br>
xlsxwriter: None<br>
lxml: None<br>
bs4: None<br>
html5lib: 0.999<br>
sqlalchemy: None<br>
pymysql: None<br>
psycopg2: None<br>
jinja2: 2.9.6<br>
s3fs: None<br>
pandas_gbq: None<br>
pandas_datareader: None</p>
</details>
<p dir="auto">A few of the methods in <code class="notranslate">groupby_helper.pxi.in</code> have a pattern that goes:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="
    N, K = (&lt;object&gt; values).shape

    with nogil:

        if K &gt; 1:
            # loop over j in range(K) and do stuff
            ...
        else:
            # do stuff with j=0
            ..."><pre class="notranslate">    <span class="pl-v">N</span>, <span class="pl-v">K</span> <span class="pl-c1">=</span> (<span class="pl-c1">&lt;</span><span class="pl-s1">object</span><span class="pl-c1">&gt;</span> <span class="pl-s1">values</span>).<span class="pl-s1">shape</span>

    <span class="pl-k">with</span> <span class="pl-s1">nogil</span>:

        <span class="pl-k">if</span> <span class="pl-v">K</span> <span class="pl-c1">&gt;</span> <span class="pl-c1">1</span>:
            <span class="pl-c"># loop over j in range(K) and do stuff</span>
            ...
        <span class="pl-k">else</span>:
            <span class="pl-c"># do stuff with j=0</span>
            ...</pre></div>
<p dir="auto">Unless I'm missing something simple I don't think there's a reason to have the conditional and duplicate code branches. In the case where K=1 (which is all the time?) then the <code class="notranslate">for j in range(K)</code> construct inherently sets <code class="notranslate">j=0</code>, bypassing the need for the conditional</p>