polars-df 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,104 @@
1
+ module Polars
2
+ # @private
3
+ class Slice
4
+ def initialize(obj)
5
+ @obj = obj
6
+ end
7
+
8
+ # Apply a slice operation, taking advantage of any potential fast paths.
9
+ def apply(s)
10
+ # normalize slice
11
+ _slice_setup(s)
12
+
13
+ # check for fast-paths / single-operation calls
14
+ if @slice_length == 0
15
+ @obj.cleared
16
+ elsif @is_unbounded && [-1, 1].include?(@stride)
17
+ @stride < 0 ? @obj.reverse : @obj.clone
18
+ elsif @start >= 0 && @stop >= 0 && @stride == 1
19
+ @obj.slice(@start, @slice_length)
20
+ elsif @stride < 0 && @slice_length == 1
21
+ @obj.slice(@stop + 1, 1)
22
+ else
23
+ # multi-operation calls; make lazy
24
+ lazyobj = _lazify(@obj)
25
+ sliced = @stride > 0 ? _slice_positive(lazyobj) : _slice_negative(lazyobj)
26
+ _as_original(sliced, @obj)
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ # Return lazy variant back to its original type.
33
+ def _as_original(lazy, original)
34
+ frame = lazy.collect
35
+ original.is_a?(DataFrame) ? frame : frame.to_series
36
+ end
37
+
38
+ # Make lazy to ensure efficient/consistent handling.
39
+ def _lazify(obj)
40
+ obj.is_a?(DataFrame) ? obj.lazy : obj.to_frame.lazy
41
+ end
42
+
43
+ # Logic for slices with positive stride.
44
+ def _slice_positive(obj)
45
+ # note: at this point stride is guaranteed to be > 1
46
+ obj.slice(@start, @slice_length).take_every(@stride)
47
+ end
48
+
49
+ # Logic for slices with negative stride.
50
+ def _slice_negative(obj)
51
+ stride = @stride.abs
52
+ lazyslice = obj.slice(@stop + 1, @slice_length).reverse
53
+ stride > 1 ? lazyslice.take_every(stride) : lazyslice
54
+ end
55
+
56
+ # Normalize slice bounds, identify unbounded and/or zero-length slices.
57
+ def _slice_setup(s)
58
+ # can normalize slice indices as we know object size
59
+ obj_len = @obj.len
60
+ start = if s.begin
61
+ if s.begin < 0
62
+ [s.begin + obj_len, 0].max
63
+ else
64
+ s.begin
65
+ end
66
+ else
67
+ 0
68
+ end
69
+ stop = if s.end
70
+ if s.end < 0
71
+ s.end + (s.exclude_end? ? 0 : 1) + obj_len
72
+ else
73
+ s.end + (s.exclude_end? ? 0 : 1)
74
+ end
75
+ else
76
+ obj_len
77
+ end
78
+ stride = 1
79
+
80
+ # check if slice is actually unbounded
81
+ if stride >= 1
82
+ @is_unbounded = start <= 0 && stop >= obj_len
83
+ else
84
+ @is_unbounded = stop == -1 && start >= obj_len - 1
85
+ end
86
+
87
+ # determine slice length
88
+ if @obj.is_empty
89
+ @slice_length = 0
90
+ elsif @is_unbounded
91
+ @slice_length = obj_len
92
+ else
93
+ @slice_length = if start == stop || (stride > 0 && start > stop) || (stride < 0 && start < stop)
94
+ 0
95
+ else
96
+ (stop - start).abs
97
+ end
98
+ end
99
+ @start = start
100
+ @stop = stop
101
+ @stride = stride
102
+ end
103
+ end
104
+ end