Repository: pandas-dev/pandas

Issue:
BUG: Merge with empty DataFrame raise IndexError
```
import numpy as np
import pandas as pd

df1 = pd.DataFrame([], columns=['a', 'b', 'c'])
df2 = pd.DataFrame(np.random.randn(3, 3), columns=['x', 'y', 'z'])

# OK
pd.merge(df1, df2, how='right', left_index=True, right_index=True)
#      a    b    c         x         y         z
#0  NaN  NaN  NaN  0.665359  0.087728 -0.608138
#1  NaN  NaN  NaN -0.730847  0.882151  0.175648
#2  NaN  NaN  NaN  2.370834 -1.347337 -0.478547

pd.merge(df1, df2, how='outer', left_index=True, right_index=True)
#      a    b    c         x         y         z
#0  NaN  NaN  NaN  0.665359  0.087728 -0.608138
#1  NaN  NaN  NaN -0.730847  0.882151  0.175648
#2  NaN  NaN  NaN  2.370834 -1.347337 -0.478547

# NG, this should be the same as above
pd.merge(df1, df2, how='right', left_on='a', right_index=True)
# IndexError: cannot do a non-empty take from an empty axes.

pd.merge(df1, df2, how='outer', left_on='a', right_index=True)
# IndexError: cannot do a non-empty take from an empty axes.
```

This works if both `DataFrame` are empty.

```
df1 = pd.DataFrame([], columns=['a', 'b', 'c'])
df2 = pd.DataFrame([], columns=['x', 'y', 'z'])

pd.merge(df1, df2, how='right', left_on='a', right_index=True)
# Empty DataFrame
# Columns: [a, b, c, x, y, z]
# Index: []

pd.merge(df1, df2, how='outer', left_on='a', right_index=True)
# Empty DataFrame
# Columns: [a, b, c, x, y, z]
# Index: []
```



Discussion:

Resolving patch:
diff --git a/pandas/tools/merge.py b/pandas/tools/merge.py
--- a/pandas/tools/merge.py
+++ b/pandas/tools/merge.py
@@ -217,6 +217,9 @@ def _maybe_add_join_keys(self, result, left_indexer, right_indexer):
                 if left_indexer is not None and right_indexer is not None:
 
                     if name in self.left:
+                        if len(self.left) == 0:
+                            continue
+
                         na_indexer = (left_indexer == -1).nonzero()[0]
                         if len(na_indexer) == 0:
                             continue
@@ -226,6 +229,9 @@ def _maybe_add_join_keys(self, result, left_indexer, right_indexer):
                             na_indexer, com.take_1d(self.right_join_keys[i],
                                                     right_na_indexer))
                     elif name in self.right:
+                        if len(self.right) == 0:
+                            continue
+
                         na_indexer = (right_indexer == -1).nonzero()[0]
                         if len(na_indexer) == 0:
                             continue
@@ -270,9 +276,17 @@ def _get_join_info(self):
                                                  sort=self.sort, how=self.how)
 
             if self.right_index:
-                join_index = self.left.index.take(left_indexer)
+                if len(self.left) > 0:
+                    join_index = self.left.index.take(left_indexer)
+                else:
+                    join_index = self.right.index.take(right_indexer)
+                    left_indexer = np.array([-1] * len(join_index))
             elif self.left_index:
-                join_index = self.right.index.take(right_indexer)
+                if len(self.right) > 0:
+                    join_index = self.right.index.take(right_indexer)
+                else:
+                    join_index = self.left.index.take(left_indexer)
+                    right_indexer = np.array([-1] * len(join_index))
             else:
                 join_index = Index(np.arange(len(left_indexer)))
 


Test patch:
diff --git a/pandas/tools/tests/test_merge.py b/pandas/tools/tests/test_merge.py
--- a/pandas/tools/tests/test_merge.py
+++ b/pandas/tools/tests/test_merge.py
@@ -737,6 +737,88 @@ def test_left_merge_empty_dataframe(self):
         result = merge(right, left, on='key', how='right')
         assert_frame_equal(result, left)
 
+    def test_merge_left_empty_right_empty(self):
+        # GH 10824
+        left = pd.DataFrame([], columns=['a', 'b', 'c'])
+        right = pd.DataFrame([], columns=['x', 'y', 'z'])
+
+        exp_in = pd.DataFrame([], columns=['a', 'b', 'c', 'x', 'y', 'z'],
+                              dtype=object)
+
+        for kwarg in [dict(left_index=True, right_index=True),
+                      dict(left_index=True, right_on='x'),
+                      dict(left_on='a', right_index=True),
+                      dict(left_on='a', right_on='x')]:
+
+            result = pd.merge(left, right, how='inner', **kwarg)
+            tm.assert_frame_equal(result, exp_in)
+            result = pd.merge(left, right, how='left', **kwarg)
+            tm.assert_frame_equal(result, exp_in)
+            result = pd.merge(left, right, how='right', **kwarg)
+            tm.assert_frame_equal(result, exp_in)
+            result = pd.merge(left, right, how='outer', **kwarg)
+            tm.assert_frame_equal(result, exp_in)
+
+    def test_merge_left_empty_right_notempty(self):
+        # GH 10824
+        left = pd.DataFrame([], columns=['a', 'b', 'c'])
+        right = pd.DataFrame([[1, 2, 3], [4, 5, 6], [7, 8, 9]],
+                             columns=['x', 'y', 'z'])
+
+        exp_out = pd.DataFrame({'a': np.array([np.nan]*3, dtype=object),
+                                'b': np.array([np.nan]*3, dtype=object),
+                                'c': np.array([np.nan]*3, dtype=object),
+                                'x': [1, 4, 7],
+                                'y': [2, 5, 8],
+                                'z': [3, 6, 9]},
+                               columns=['a', 'b', 'c', 'x', 'y', 'z'])
+        exp_in = exp_out[0:0] # make empty DataFrame keeping dtype
+
+        for kwarg in [dict(left_index=True, right_index=True),
+                      dict(left_index=True, right_on='x'),
+                      dict(left_on='a', right_index=True),
+                      dict(left_on='a', right_on='x')]:
+
+            result = pd.merge(left, right, how='inner', **kwarg)
+            tm.assert_frame_equal(result, exp_in)
+            result = pd.merge(left, right, how='left', **kwarg)
+            tm.assert_frame_equal(result, exp_in)
+
+            result = pd.merge(left, right, how='right', **kwarg)
+            tm.assert_frame_equal(result, exp_out)
+            result = pd.merge(left, right, how='outer', **kwarg)
+            tm.assert_frame_equal(result, exp_out)
+
+    def test_merge_left_notempty_right_empty(self):
+        # GH 10824
+        left = pd.DataFrame([[1, 2, 3], [4, 5, 6], [7, 8, 9]],
+                            columns=['a', 'b', 'c'])
+        right = pd.DataFrame([], columns=['x', 'y', 'z'])
+
+        exp_out = pd.DataFrame({'a': [1, 4, 7],
+                                'b': [2, 5, 8],
+                                'c': [3, 6, 9],
+                                'x': np.array([np.nan]*3, dtype=object),
+                                'y': np.array([np.nan]*3, dtype=object),
+                                'z': np.array([np.nan]*3, dtype=object)},
+                               columns=['a', 'b', 'c', 'x', 'y', 'z'])
+        exp_in = exp_out[0:0] # make empty DataFrame keeping dtype
+
+        for kwarg in [dict(left_index=True, right_index=True),
+                      dict(left_index=True, right_on='x'),
+                      dict(left_on='a', right_index=True),
+                      dict(left_on='a', right_on='x')]:
+
+            result = pd.merge(left, right, how='inner', **kwarg)
+            tm.assert_frame_equal(result, exp_in)
+            result = pd.merge(left, right, how='right', **kwarg)
+            tm.assert_frame_equal(result, exp_in)
+
+            result = pd.merge(left, right, how='left', **kwarg)
+            tm.assert_frame_equal(result, exp_out)
+            result = pd.merge(left, right, how='outer', **kwarg)
+            tm.assert_frame_equal(result, exp_out)
+
     def test_merge_nosort(self):
         # #2098, anything to do?