Repository: databricks/koalas

Issue:
Support slice as `rows_sel` for `iloc` indexer.
Now that we have an infrastructure to support slice as `rows_sel` for `iloc` indexer.
E.g.,

```py
>>> pdf = pd.DataFrame({'a':list('abcdefghij')})
>>> pdf
   a
0  a
1  b
2  c
3  d
4  e
5  f
6  g
7  h
8  i
9  j
>>> pdf.iloc[2:5]
   a
2  c
3  d
4  e
>>> pdf.iloc[2:-3]
   a
2  c
3  d
4  e
5  f
6  g
>>> pdf.iloc[-8:-3]
   a
2  c
3  d
4  e
5  f
6  g
>>> pdf.iloc[2:-3:2]
   a
2  c
4  e
6  g
>>> pdf.iloc[5:]
   a
5  f
6  g
7  h
8  i
9  j
>>> pdf.iloc[5:2]
Empty DataFrame
Columns: [a]
Index: []
```



Discussion:

Resolving patch:
diff --git a/databricks/koalas/indexing.py b/databricks/koalas/indexing.py
--- a/databricks/koalas/indexing.py
+++ b/databricks/koalas/indexing.py
@@ -933,19 +933,69 @@ def _select_rows(self, rows_sel):
             assert isinstance(rows_sel.spark_type, BooleanType), rows_sel.spark_type
             return rows_sel._scol, None, None
         elif isinstance(rows_sel, slice):
-            if rows_sel == slice(None):
-                # If slice is None - select everything, so nothing to do
-                return None, None, None
-            elif (rows_sel.start is not None) or (rows_sel.step is not None):
-                iLocIndexer._raiseNotImplemented("Cannot use start or step with Spark.")
-            elif not isinstance(rows_sel.stop, int):
-                raise TypeError(
-                    "cannot do slice indexing with these indexers [{}] of {}".format(
-                        rows_sel.stop, type(rows_sel.stop)
+
+            def verify_type(i):
+                if not isinstance(i, int):
+                    raise TypeError(
+                        "cannot do slice indexing with these indexers [{}] of {}".format(i, type(i))
                     )
-                )
+
+            has_negative = False
+            start = rows_sel.start
+            if start is not None:
+                verify_type(start)
+                if start == 0:
+                    start = None
+                elif start < 0:
+                    has_negative = True
+            stop = rows_sel.stop
+            if stop is not None:
+                verify_type(stop)
+                if stop == 0:
+                    stop = None
+                elif stop < 0:
+                    has_negative = True
+
+            step = rows_sel.step
+            if step is not None:
+                verify_type(step)
+                if step == 0:
+                    raise ValueError("slice step cannot be zero")
             else:
-                return None, rows_sel.stop, None
+                step = 1
+
+            if start is None and step == 1:
+                return None, stop, None
+
+            sdf = self._internal.spark_frame
+            sequence_scol = sdf[self._sequence_col]
+
+            if has_negative or (step < 0 and start is None):
+                cnt = sdf.count()
+
+            cond = []
+            if start is not None:
+                if start < 0:
+                    start = start + cnt
+                if step >= 0:
+                    cond.append(sequence_scol >= F.lit(start).cast(LongType()))
+                else:
+                    cond.append(sequence_scol <= F.lit(start).cast(LongType()))
+            if stop is not None:
+                if stop < 0:
+                    stop = stop + cnt
+                if step >= 0:
+                    cond.append(sequence_scol < F.lit(stop).cast(LongType()))
+                else:
+                    cond.append(sequence_scol > F.lit(stop).cast(LongType()))
+            if step != 1:
+                if step > 0:
+                    start = start or 0
+                else:
+                    start = start or (cnt - 1)
+                cond.append(((sequence_scol - start) % F.lit(step).cast(LongType())) == F.lit(0))
+
+            return reduce(lambda x, y: x & y, cond), None, None
         elif isinstance(rows_sel, int):
             sdf = self._internal.spark_frame
             return (sdf[self._sequence_col] == rows_sel), None, 0


Test patch:
diff --git a/databricks/koalas/tests/test_indexing.py b/databricks/koalas/tests/test_indexing.py
--- a/databricks/koalas/tests/test_indexing.py
+++ b/databricks/koalas/tests/test_indexing.py
@@ -673,6 +673,27 @@ def test_iloc_series(self):
         self.assert_eq(kseries.iloc[:1], pseries.iloc[:1])
         self.assert_eq(kseries.iloc[:-1], pseries.iloc[:-1])
 
+    def test_iloc_slice_rows_sel(self):
+        pdf = pd.DataFrame({"A": [1, 2] * 5, "B": [3, 4] * 5, "C": [5, 6] * 5})
+        kdf = ks.from_pandas(pdf)
+
+        for rows_sel in [
+            slice(None),
+            slice(0, 1),
+            slice(1, 2),
+            slice(-3, None),
+            slice(None, -3),
+            slice(None, None, 3),
+            slice(3, 8, 2),
+            slice(None, None, -2),
+            slice(8, 3, -2),
+            slice(8, None, -2),
+            slice(None, 3, -2),
+        ]:
+            with self.subTest(rows_sel=rows_sel):
+                self.assert_eq(kdf.iloc[rows_sel].sort_index(), pdf.iloc[rows_sel].sort_index())
+                self.assert_eq(kdf.A.iloc[rows_sel].sort_index(), pdf.A.iloc[rows_sel].sort_index())
+
     def test_setitem(self):
         pdf = pd.DataFrame(
             [[1, 2], [4, 5], [7, 8]],
@@ -714,16 +735,6 @@ def test_iloc_raises(self):
         pdf = pd.DataFrame({"A": [1, 2], "B": [3, 4], "C": [5, 6]})
         kdf = ks.from_pandas(pdf)
 
-        with self.assertRaisesRegex(
-            SparkPandasNotImplementedError, "Cannot use start or step with Spark."
-        ):
-            kdf.iloc[0:]
-
-        with self.assertRaisesRegex(
-            SparkPandasNotImplementedError, "Cannot use start or step with Spark."
-        ):
-            kdf.iloc[:2:2]
-
         with self.assertRaisesRegex(
             SparkPandasNotImplementedError,
             ".iloc requires numeric slice or conditional boolean Index",