polars-df 0.15.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +274 -0
  3. data/Cargo.lock +1465 -867
  4. data/Cargo.toml +3 -0
  5. data/LICENSE.txt +2 -2
  6. data/README.md +87 -37
  7. data/ext/polars/Cargo.toml +47 -16
  8. data/ext/polars/src/c_api/allocator.rs +7 -0
  9. data/ext/polars/src/c_api/mod.rs +1 -0
  10. data/ext/polars/src/catalog/mod.rs +1 -0
  11. data/ext/polars/src/catalog/unity.rs +470 -0
  12. data/ext/polars/src/conversion/any_value.rs +99 -84
  13. data/ext/polars/src/conversion/categorical.rs +30 -0
  14. data/ext/polars/src/conversion/chunked_array.rs +71 -62
  15. data/ext/polars/src/conversion/datetime.rs +63 -0
  16. data/ext/polars/src/conversion/mod.rs +796 -312
  17. data/ext/polars/src/dataframe/construction.rs +6 -18
  18. data/ext/polars/src/dataframe/export.rs +30 -39
  19. data/ext/polars/src/dataframe/general.rs +294 -362
  20. data/ext/polars/src/dataframe/io.rs +33 -150
  21. data/ext/polars/src/dataframe/map.rs +175 -0
  22. data/ext/polars/src/dataframe/mod.rs +37 -5
  23. data/ext/polars/src/dataframe/serde.rs +23 -8
  24. data/ext/polars/src/error.rs +44 -7
  25. data/ext/polars/src/exceptions.rs +21 -8
  26. data/ext/polars/src/expr/array.rs +86 -22
  27. data/ext/polars/src/expr/binary.rs +50 -1
  28. data/ext/polars/src/expr/bitwise.rs +39 -0
  29. data/ext/polars/src/expr/categorical.rs +20 -0
  30. data/ext/polars/src/expr/datatype.rs +51 -0
  31. data/ext/polars/src/expr/datetime.rs +99 -41
  32. data/ext/polars/src/expr/extension.rs +12 -0
  33. data/ext/polars/src/expr/general.rs +252 -128
  34. data/ext/polars/src/expr/list.rs +56 -60
  35. data/ext/polars/src/expr/meta.rs +30 -35
  36. data/ext/polars/src/expr/mod.rs +28 -6
  37. data/ext/polars/src/expr/name.rs +29 -14
  38. data/ext/polars/src/expr/rolling.rs +111 -3
  39. data/ext/polars/src/expr/selector.rs +219 -0
  40. data/ext/polars/src/expr/serde.rs +28 -0
  41. data/ext/polars/src/expr/string.rs +118 -20
  42. data/ext/polars/src/expr/struct.rs +14 -1
  43. data/ext/polars/src/file.rs +194 -86
  44. data/ext/polars/src/functions/aggregation.rs +13 -12
  45. data/ext/polars/src/functions/business.rs +2 -3
  46. data/ext/polars/src/functions/eager.rs +3 -2
  47. data/ext/polars/src/functions/io.rs +90 -18
  48. data/ext/polars/src/functions/lazy.rs +267 -118
  49. data/ext/polars/src/functions/meta.rs +8 -7
  50. data/ext/polars/src/functions/misc.rs +1 -1
  51. data/ext/polars/src/functions/mod.rs +2 -1
  52. data/ext/polars/src/functions/range.rs +88 -31
  53. data/ext/polars/src/functions/strings.rs +6 -0
  54. data/ext/polars/src/functions/utils.rs +8 -0
  55. data/ext/polars/src/interop/arrow/mod.rs +52 -1
  56. data/ext/polars/src/interop/arrow/{to_ruby.rs → to_rb.rs} +37 -7
  57. data/ext/polars/src/interop/arrow/to_rust.rs +43 -0
  58. data/ext/polars/src/interop/numo/to_numo_df.rs +1 -1
  59. data/ext/polars/src/interop/numo/to_numo_series.rs +72 -50
  60. data/ext/polars/src/io/cloud_options.rs +107 -0
  61. data/ext/polars/src/io/mod.rs +4 -0
  62. data/ext/polars/src/io/scan_options.rs +113 -0
  63. data/ext/polars/src/io/sink_options.rs +46 -0
  64. data/ext/polars/src/io/sink_output.rs +21 -0
  65. data/ext/polars/src/lazyframe/exitable.rs +39 -0
  66. data/ext/polars/src/lazyframe/general.rs +846 -368
  67. data/ext/polars/src/lazyframe/mod.rs +58 -5
  68. data/ext/polars/src/lazyframe/optflags.rs +59 -0
  69. data/ext/polars/src/lazyframe/serde.rs +36 -4
  70. data/ext/polars/src/lazyframe/sink.rs +46 -0
  71. data/ext/polars/src/lazygroupby.rs +38 -9
  72. data/ext/polars/src/lib.rs +574 -165
  73. data/ext/polars/src/map/lazy.rs +44 -74
  74. data/ext/polars/src/map/mod.rs +18 -254
  75. data/ext/polars/src/map/series.rs +241 -1087
  76. data/ext/polars/src/on_startup.rs +192 -9
  77. data/ext/polars/src/prelude.rs +1 -0
  78. data/ext/polars/src/rb_modules.rs +10 -57
  79. data/ext/polars/src/ruby/exceptions.rs +26 -0
  80. data/ext/polars/src/ruby/gvl.rs +104 -0
  81. data/ext/polars/src/ruby/lazy.rs +46 -0
  82. data/ext/polars/src/ruby/mod.rs +11 -0
  83. data/ext/polars/src/ruby/numo.rs +52 -0
  84. data/ext/polars/src/ruby/plan_callback.rs +198 -0
  85. data/ext/polars/src/ruby/rb_modules.rs +16 -0
  86. data/ext/polars/src/ruby/ruby_convert_registry.rs +51 -0
  87. data/ext/polars/src/ruby/ruby_function.rs +11 -0
  88. data/ext/polars/src/ruby/ruby_udf.rs +164 -0
  89. data/ext/polars/src/ruby/thread.rs +65 -0
  90. data/ext/polars/src/ruby/utils.rs +39 -0
  91. data/ext/polars/src/series/aggregation.rs +116 -91
  92. data/ext/polars/src/series/arithmetic.rs +16 -22
  93. data/ext/polars/src/series/comparison.rs +101 -222
  94. data/ext/polars/src/series/construction.rs +80 -70
  95. data/ext/polars/src/series/export.rs +98 -56
  96. data/ext/polars/src/series/general.rs +323 -440
  97. data/ext/polars/src/series/import.rs +22 -5
  98. data/ext/polars/src/series/map.rs +103 -0
  99. data/ext/polars/src/series/mod.rs +57 -15
  100. data/ext/polars/src/series/scatter.rs +139 -82
  101. data/ext/polars/src/sql.rs +16 -9
  102. data/ext/polars/src/testing/frame.rs +31 -0
  103. data/ext/polars/src/testing/mod.rs +5 -0
  104. data/ext/polars/src/testing/series.rs +31 -0
  105. data/ext/polars/src/timeout.rs +105 -0
  106. data/ext/polars/src/utils.rs +105 -4
  107. data/lib/polars/array_expr.rb +500 -22
  108. data/lib/polars/array_name_space.rb +384 -10
  109. data/lib/polars/batched_csv_reader.rb +48 -66
  110. data/lib/polars/binary_expr.rb +217 -0
  111. data/lib/polars/binary_name_space.rb +155 -1
  112. data/lib/polars/cat_expr.rb +224 -0
  113. data/lib/polars/cat_name_space.rb +132 -32
  114. data/lib/polars/catalog/unity/catalog_info.rb +20 -0
  115. data/lib/polars/catalog/unity/column_info.rb +31 -0
  116. data/lib/polars/catalog/unity/namespace_info.rb +21 -0
  117. data/lib/polars/catalog/unity/table_info.rb +50 -0
  118. data/lib/polars/catalog.rb +448 -0
  119. data/lib/polars/collect_batches.rb +22 -0
  120. data/lib/polars/config.rb +3 -3
  121. data/lib/polars/convert.rb +201 -36
  122. data/lib/polars/data_frame.rb +2851 -1017
  123. data/lib/polars/data_frame_plot.rb +173 -0
  124. data/lib/polars/data_type_expr.rb +52 -0
  125. data/lib/polars/data_type_group.rb +6 -0
  126. data/lib/polars/data_types.rb +118 -18
  127. data/lib/polars/date_time_expr.rb +426 -84
  128. data/lib/polars/date_time_name_space.rb +384 -111
  129. data/lib/polars/dynamic_group_by.rb +102 -10
  130. data/lib/polars/exceptions.rb +50 -5
  131. data/lib/polars/expr.rb +2159 -915
  132. data/lib/polars/extension_expr.rb +39 -0
  133. data/lib/polars/extension_name_space.rb +39 -0
  134. data/lib/polars/functions/aggregation/horizontal.rb +11 -6
  135. data/lib/polars/functions/aggregation/vertical.rb +2 -3
  136. data/lib/polars/functions/as_datatype.rb +290 -8
  137. data/lib/polars/functions/business.rb +95 -0
  138. data/lib/polars/functions/col.rb +6 -5
  139. data/lib/polars/functions/datatype.rb +62 -0
  140. data/lib/polars/functions/eager.rb +426 -24
  141. data/lib/polars/functions/escape_regex.rb +21 -0
  142. data/lib/polars/functions/lazy.rb +813 -195
  143. data/lib/polars/functions/lit.rb +21 -10
  144. data/lib/polars/functions/range/int_range.rb +74 -2
  145. data/lib/polars/functions/range/linear_space.rb +195 -0
  146. data/lib/polars/functions/range/time_range.rb +1 -1
  147. data/lib/polars/functions/repeat.rb +7 -12
  148. data/lib/polars/functions/whenthen.rb +2 -2
  149. data/lib/polars/group_by.rb +188 -58
  150. data/lib/polars/iceberg_dataset.rb +108 -0
  151. data/lib/polars/in_process_query.rb +37 -0
  152. data/lib/polars/io/cloud.rb +18 -0
  153. data/lib/polars/io/csv.rb +336 -128
  154. data/lib/polars/io/database.rb +19 -4
  155. data/lib/polars/io/delta.rb +134 -0
  156. data/lib/polars/io/iceberg.rb +34 -0
  157. data/lib/polars/io/ipc.rb +63 -63
  158. data/lib/polars/io/json.rb +16 -0
  159. data/lib/polars/io/lines.rb +172 -0
  160. data/lib/polars/io/ndjson.rb +176 -20
  161. data/lib/polars/io/parquet.rb +173 -95
  162. data/lib/polars/io/scan_options.rb +55 -0
  163. data/lib/polars/io/sink_options.rb +27 -0
  164. data/lib/polars/io/utils.rb +17 -0
  165. data/lib/polars/lazy_frame.rb +3017 -622
  166. data/lib/polars/lazy_group_by.rb +436 -2
  167. data/lib/polars/list_expr.rb +551 -59
  168. data/lib/polars/list_name_space.rb +465 -51
  169. data/lib/polars/meta_expr.rb +146 -24
  170. data/lib/polars/name_expr.rb +87 -2
  171. data/lib/polars/query_opt_flags.rb +264 -0
  172. data/lib/polars/rolling_group_by.rb +90 -5
  173. data/lib/polars/scan_cast_options.rb +86 -0
  174. data/lib/polars/schema.rb +128 -0
  175. data/lib/polars/selector.rb +245 -0
  176. data/lib/polars/selectors.rb +1048 -201
  177. data/lib/polars/series.rb +2522 -774
  178. data/lib/polars/series_plot.rb +72 -0
  179. data/lib/polars/slice.rb +1 -1
  180. data/lib/polars/sql_context.rb +13 -6
  181. data/lib/polars/string_cache.rb +19 -72
  182. data/lib/polars/string_expr.rb +561 -107
  183. data/lib/polars/string_name_space.rb +781 -109
  184. data/lib/polars/struct_expr.rb +139 -18
  185. data/lib/polars/struct_name_space.rb +19 -1
  186. data/lib/polars/testing.rb +24 -273
  187. data/lib/polars/utils/constants.rb +2 -0
  188. data/lib/polars/utils/construction/data_frame.rb +410 -0
  189. data/lib/polars/utils/construction/series.rb +350 -0
  190. data/lib/polars/utils/construction/utils.rb +9 -0
  191. data/lib/polars/utils/convert.rb +18 -8
  192. data/lib/polars/utils/deprecation.rb +11 -0
  193. data/lib/polars/utils/parse.rb +62 -9
  194. data/lib/polars/utils/reduce_balanced.rb +43 -0
  195. data/lib/polars/utils/serde.rb +22 -0
  196. data/lib/polars/utils/unstable.rb +19 -0
  197. data/lib/polars/utils/various.rb +86 -1
  198. data/lib/polars/utils.rb +63 -48
  199. data/lib/polars/version.rb +1 -1
  200. data/lib/polars.rb +85 -2
  201. metadata +80 -28
  202. data/ext/polars/src/allocator.rs +0 -13
  203. data/ext/polars/src/batched_csv.rs +0 -138
  204. data/ext/polars/src/functions/string_cache.rs +0 -25
  205. data/ext/polars/src/map/dataframe.rs +0 -338
  206. data/lib/polars/plot.rb +0 -109
@@ -1,118 +1,5 @@
1
1
  module Polars
2
2
  module Selectors
3
- # @private
4
- class SelectorProxy < Expr
5
- attr_accessor :_attrs
6
- attr_accessor :_repr_override
7
-
8
- def initialize(
9
- expr,
10
- name:,
11
- parameters: nil
12
- )
13
- self._rbexpr = expr._rbexpr
14
- self._attrs = {
15
- name: name,
16
- params: parameters
17
- }
18
- end
19
-
20
- def inspect
21
- if !_attrs
22
- as_expr.inspect
23
- elsif _repr_override
24
- _repr_override
25
- else
26
- selector_name = _attrs[:name]
27
- params = _attrs[:params] || {}
28
- set_ops = {"and" => "&", "or" => "|", "sub" => "-", "xor" => "^"}
29
- if set_ops.include?(selector_name)
30
- op = set_ops[selector_name]
31
- "(#{params.values.map(&:inspect).join(" #{op} ")})"
32
- else
33
- str_params = params.map { |k, v| k.start_with?("*") ? v.inspect[1..-2] : "#{k}=#{v.inspect}" }.join(", ")
34
- "Polars.cs.#{selector_name}(#{str_params})"
35
- end
36
- end
37
- end
38
-
39
- def ~
40
- if Utils.is_selector(self)
41
- inverted = Selectors.all - self
42
- inverted._repr_override = "~#{inspect}"
43
- else
44
- inverted = ~as_expr
45
- end
46
- inverted
47
- end
48
-
49
- def -(other)
50
- if Utils.is_selector(other)
51
- SelectorProxy.new(
52
- meta._as_selector.meta._selector_sub(other),
53
- parameters: {"self" => self, "other" => other},
54
- name: "sub"
55
- )
56
- else
57
- as_expr - other
58
- end
59
- end
60
-
61
- def &(other)
62
- if Utils.is_column(other)
63
- raise Todo
64
- end
65
- if Utils.is_selector(other)
66
- SelectorProxy.new(
67
- meta._as_selector.meta._selector_and(other),
68
- parameters: {"self" => self, "other" => other},
69
- name: "and"
70
- )
71
- else
72
- as_expr & other
73
- end
74
- end
75
-
76
- def |(other)
77
- if Utils.is_column(other)
78
- raise Todo
79
- end
80
- if Utils.is_selector(other)
81
- SelectorProxy.new(
82
- meta._as_selector.meta._selector_and(other),
83
- parameters: {"self" => self, "other" => other},
84
- name: "or"
85
- )
86
- else
87
- as_expr | other
88
- end
89
- end
90
-
91
- def ^(other)
92
- if Utils.is_column(other)
93
- raise Todo
94
- end
95
- if Utils.is_selector(other)
96
- SelectorProxy.new(
97
- meta._as_selector.meta._selector_and(other),
98
- parameters: {"self" => self, "other" => other},
99
- name: "xor"
100
- )
101
- else
102
- as_expr ^ other
103
- end
104
- end
105
-
106
- def as_expr
107
- Expr._from_rbexpr(_rbexpr)
108
- end
109
- end
110
-
111
- # @private
112
- def self._selector_proxy_(...)
113
- SelectorProxy.new(...)
114
- end
115
-
116
3
  # @private
117
4
  def self._re_string(string, escape: true)
118
5
  if string.is_a?(::String)
@@ -131,11 +18,28 @@ module Polars
131
18
  "(#{rx})"
132
19
  end
133
20
 
134
- # Select all columns.
21
+ # Select no columns.
135
22
  #
136
- # @return [SelectorProxy]
23
+ # This is useful for composition with other selectors.
24
+ #
25
+ # @return [Selector]
137
26
  #
138
27
  # @example
28
+ # Polars::DataFrame.new({"a" => 1, "b" => 2}).select(Polars.cs.empty)
29
+ # # =>
30
+ # # shape: (0, 0)
31
+ # # ┌┐
32
+ # # ╞╡
33
+ # # └┘
34
+ def self.empty
35
+ Selector._from_rbselector(RbSelector.empty)
36
+ end
37
+
38
+ # Select all columns.
39
+ #
40
+ # @return [Selector]
41
+ #
42
+ # @example Select all columns, casting them to string:
139
43
  # df = Polars::DataFrame.new(
140
44
  # {
141
45
  # "dt" => [Date.new(1999, 12, 31), Date.new(2024, 1, 1)],
@@ -143,8 +47,6 @@ module Polars
143
47
  # },
144
48
  # schema_overrides: {"value" => Polars::Int32}
145
49
  # )
146
- #
147
- # @example Select all columns, casting them to string:
148
50
  # df.select(Polars.cs.all.cast(Polars::String))
149
51
  # # =>
150
52
  # # shape: (2, 2)
@@ -170,7 +72,7 @@ module Polars
170
72
  # # │ 2024-01-01 │
171
73
  # # └────────────┘
172
74
  def self.all
173
- _selector_proxy_(F.all, name: "all")
75
+ Selector._from_rbselector(RbSelector.all)
174
76
  end
175
77
 
176
78
  # Select all columns with alphabetic names (eg: only letters).
@@ -182,7 +84,7 @@ module Polars
182
84
  # Indicate whether to ignore the presence of spaces in column names; if so,
183
85
  # only the other (non-space) characters are considered.
184
86
  #
185
- # @return [SelectorProxy]
87
+ # @return [Selector]
186
88
  #
187
89
  # @note
188
90
  # Matching column names cannot contain *any* non-alphabetic characters. Note
@@ -274,20 +176,102 @@ module Polars
274
176
  # note that we need to supply a pattern compatible with the *rust* regex crate
275
177
  re_alpha = ascii_only ? "a-zA-Z" : "\\p{Alphabetic}"
276
178
  re_space = ignore_spaces ? " " : ""
277
- _selector_proxy_(
278
- F.col("^[#{re_alpha}#{re_space}]+$"),
279
- name: "alpha",
280
- parameters: {"ascii_only" => ascii_only, "ignore_spaces" => ignore_spaces},
281
- )
179
+ Selector._from_rbselector(RbSelector.matches("^[#{re_alpha}#{re_space}]+$"))
282
180
  end
283
181
 
284
- # TODO
285
- # def alphanumeric
286
- # end
182
+ # Select all columns with alphanumeric names (eg: only letters and the digits 0-9).
183
+ #
184
+ # @param ascii_only [Boolean]
185
+ # Indicate whether to consider only ASCII alphabetic characters, or the full
186
+ # Unicode range of valid letters (accented, idiographic, etc).
187
+ # @param ignore_spaces [Boolean]
188
+ # Indicate whether to ignore the presence of spaces in column names; if so,
189
+ # only the other (non-space) characters are considered.
190
+ #
191
+ # @return [Selector]
192
+ #
193
+ # @note
194
+ # Matching column names cannot contain *any* non-alphabetic or integer characters.
195
+ # Note that the definition of "alphabetic" consists of all valid Unicode alphabetic
196
+ # characters (`\p{Alphabetic}`) and digit characters (`\d`) by default; this
197
+ # can be changed by setting `ascii_only: true`.
198
+ #
199
+ # @example Select columns with alphanumeric names:
200
+ # df = Polars::DataFrame.new(
201
+ # {
202
+ # "1st_col" => [100, 200, 300],
203
+ # "flagged" => [true, false, true],
204
+ # "00prefix" => ["01:aa", "02:bb", "03:cc"],
205
+ # "last col" => ["x", "y", "z"]
206
+ # }
207
+ # )
208
+ # df.select(Polars.cs.alphanumeric)
209
+ # # =>
210
+ # # shape: (3, 2)
211
+ # # ┌─────────┬──────────┐
212
+ # # │ flagged ┆ 00prefix │
213
+ # # │ --- ┆ --- │
214
+ # # │ bool ┆ str │
215
+ # # ╞═════════╪══════════╡
216
+ # # │ true ┆ 01:aa │
217
+ # # │ false ┆ 02:bb │
218
+ # # │ true ┆ 03:cc │
219
+ # # └─────────┴──────────┘
220
+ #
221
+ # @example
222
+ # df.select(Polars.cs.alphanumeric(ignore_spaces: true))
223
+ # # =>
224
+ # # shape: (3, 3)
225
+ # # ┌─────────┬──────────┬──────────┐
226
+ # # │ flagged ┆ 00prefix ┆ last col │
227
+ # # │ --- ┆ --- ┆ --- │
228
+ # # │ bool ┆ str ┆ str │
229
+ # # ╞═════════╪══════════╪══════════╡
230
+ # # │ true ┆ 01:aa ┆ x │
231
+ # # │ false ┆ 02:bb ┆ y │
232
+ # # │ true ┆ 03:cc ┆ z │
233
+ # # └─────────┴──────────┴──────────┘
234
+ #
235
+ # @example Select all columns *except* for those with alphanumeric names:
236
+ # df.select(~Polars.cs.alphanumeric)
237
+ # # =>
238
+ # # shape: (3, 2)
239
+ # # ┌─────────┬──────────┐
240
+ # # │ 1st_col ┆ last col │
241
+ # # │ --- ┆ --- │
242
+ # # │ i64 ┆ str │
243
+ # # ╞═════════╪══════════╡
244
+ # # │ 100 ┆ x │
245
+ # # │ 200 ┆ y │
246
+ # # │ 300 ┆ z │
247
+ # # └─────────┴──────────┘
248
+ #
249
+ # @example
250
+ # df.select(~Polars.cs.alphanumeric(ignore_spaces: true))
251
+ # # =>
252
+ # # shape: (3, 1)
253
+ # # ┌─────────┐
254
+ # # │ 1st_col │
255
+ # # │ --- │
256
+ # # │ i64 │
257
+ # # ╞═════════╡
258
+ # # │ 100 │
259
+ # # │ 200 │
260
+ # # │ 300 │
261
+ # # └─────────┘
262
+ def self.alphanumeric(ascii_only: false, ignore_spaces: false)
263
+ # note that we need to supply patterns compatible with the *rust* regex crate
264
+ re_alpha = ascii_only ? "a-zA-Z" : "\\p{Alphabetic}"
265
+ re_digit = ascii_only ? "0-9" : "\\d"
266
+ re_space = ignore_spaces ? " " : ""
267
+ Selector._from_rbselector(
268
+ RbSelector.matches("^[#{re_alpha}#{re_digit}#{re_space}]+$")
269
+ )
270
+ end
287
271
 
288
272
  # Select all binary columns.
289
273
  #
290
- # @return [SelectorProxy]
274
+ # @return [Selector]
291
275
  #
292
276
  # @example
293
277
  # df = Polars::DataFrame.new({"a" => ["hello".b], "b" => ["world"], "c" => ["!".b], "d" => [":)"]})
@@ -301,7 +285,7 @@ module Polars
301
285
  # # │ b"hello" ┆ world ┆ b"!" ┆ :) │
302
286
  # # └──────────┴───────┴────────┴─────┘
303
287
  #
304
- # @example Select binary columns and export as a dict:
288
+ # @example Select binary columns and export as a hash:
305
289
  # df.select(Polars.cs.binary).to_h(as_series: false)
306
290
  # # => {"a"=>["hello"], "c"=>["!"]}
307
291
  #
@@ -309,12 +293,12 @@ module Polars
309
293
  # df.select(~Polars.cs.binary).to_h(as_series: false)
310
294
  # # => {"b"=>["world"], "d"=>[":)"]}
311
295
  def self.binary
312
- _selector_proxy_(F.col(Binary), name: "binary")
296
+ by_dtype([Binary])
313
297
  end
314
298
 
315
299
  # Select all boolean columns.
316
300
  #
317
- # @return [SelectorProxy]
301
+ # @return [Selector]
318
302
  #
319
303
  # @example
320
304
  # df = Polars::DataFrame.new({"n" => 1..4}).with_columns(n_even: Polars.col("n") % 2 == 0)
@@ -361,24 +345,550 @@ module Polars
361
345
  # # │ 4 │
362
346
  # # └─────┘
363
347
  def self.boolean
364
- _selector_proxy_(F.col(Boolean), name: "boolean")
348
+ by_dtype([Boolean])
365
349
  end
366
350
 
367
- # TODO
368
- # def by_dtype
369
- # end
351
+ # Select all columns matching the given dtypes.
352
+ #
353
+ # @return [Selector]
354
+ #
355
+ # @example Select all columns with date or string dtypes:
356
+ # df = Polars::DataFrame.new(
357
+ # {
358
+ # "dt" => [Date.new(1999, 12, 31), Date.new(2024, 1, 1), Date.new(2010, 7, 5)],
359
+ # "value" => [1_234_500, 5_000_555, -4_500_000],
360
+ # "other" => ["foo", "bar", "foo"]
361
+ # }
362
+ # )
363
+ # df.select(Polars.cs.by_dtype(Polars::Date, Polars::String))
364
+ # # =>
365
+ # # shape: (3, 2)
366
+ # # ┌────────────┬───────┐
367
+ # # │ dt ┆ other │
368
+ # # │ --- ┆ --- │
369
+ # # │ date ┆ str │
370
+ # # ╞════════════╪═══════╡
371
+ # # │ 1999-12-31 ┆ foo │
372
+ # # │ 2024-01-01 ┆ bar │
373
+ # # │ 2010-07-05 ┆ foo │
374
+ # # └────────────┴───────┘
375
+ #
376
+ # @example Select all columns that are not of date or string dtype:
377
+ # df.select(~Polars.cs.by_dtype(Polars::Date, Polars::String))
378
+ # # =>
379
+ # # shape: (3, 1)
380
+ # # ┌──────────┐
381
+ # # │ value │
382
+ # # │ --- │
383
+ # # │ i64 │
384
+ # # ╞══════════╡
385
+ # # │ 1234500 │
386
+ # # │ 5000555 │
387
+ # # │ -4500000 │
388
+ # # └──────────┘
389
+ #
390
+ # Group by string columns and sum the numeric columns:
391
+ # df.group_by(Polars.cs.string).agg(Polars.cs.numeric.sum).sort("other")
392
+ # # =>
393
+ # # shape: (2, 2)
394
+ # # ┌───────┬──────────┐
395
+ # # │ other ┆ value │
396
+ # # │ --- ┆ --- │
397
+ # # │ str ┆ i64 │
398
+ # # ╞═══════╪══════════╡
399
+ # # │ bar ┆ 5000555 │
400
+ # # │ foo ┆ -3265500 │
401
+ # # └───────┴──────────┘
402
+ def self.by_dtype(*dtypes)
403
+ all_dtypes = []
404
+ dtypes.each do |tp|
405
+ if Utils.is_polars_dtype(tp) || tp.is_a?(Class)
406
+ all_dtypes << tp
407
+ elsif tp.is_a?(::Array)
408
+ tp.each do |t|
409
+ if !(Utils.is_polars_dtype(t) || t.is_a?(Class))
410
+ msg = "invalid dtype: #{t.inspect}"
411
+ raise TypeError, msg
412
+ end
413
+ all_dtypes << t
414
+ end
415
+ else
416
+ msg = "invalid dtype: #{tp.inspect}"
417
+ raise TypeError, msg
418
+ end
419
+ end
420
+
421
+ Selector._by_dtype(all_dtypes)
422
+ end
423
+
424
+ # Select all columns matching the given indices (or range objects).
425
+ #
426
+ # @param indices [Array]
427
+ # One or more column indices (or range objects).
428
+ # Negative indexing is supported.
429
+ #
430
+ # @return [Selector]
431
+ #
432
+ # @note
433
+ # Matching columns are returned in the order in which their indexes
434
+ # appear in the selector, not the underlying schema order.
435
+ #
436
+ # @example
437
+ # df = Polars::DataFrame.new(
438
+ # {
439
+ # "key" => ["abc"],
440
+ # **100.times.to_h { |i| ["c%02d" % i, 0.5 * i] }
441
+ # }
442
+ # )
443
+ # # =>
444
+ # # shape: (1, 101)
445
+ # # ┌─────┬─────┬─────┬─────┬───┬──────┬──────┬──────┬──────┐
446
+ # # │ key ┆ c00 ┆ c01 ┆ c02 ┆ … ┆ c96 ┆ c97 ┆ c98 ┆ c99 │
447
+ # # │ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ --- ┆ --- ┆ --- │
448
+ # # │ str ┆ f64 ┆ f64 ┆ f64 ┆ ┆ f64 ┆ f64 ┆ f64 ┆ f64 │
449
+ # # ╞═════╪═════╪═════╪═════╪═══╪══════╪══════╪══════╪══════╡
450
+ # # │ abc ┆ 0.0 ┆ 0.5 ┆ 1.0 ┆ … ┆ 48.0 ┆ 48.5 ┆ 49.0 ┆ 49.5 │
451
+ # # └─────┴─────┴─────┴─────┴───┴──────┴──────┴──────┴──────┘
452
+ #
453
+ # @example Select columns by index ("key" column and the two first/last columns):
454
+ # df.select(Polars.cs.by_index(0, 1, 2, -2, -1))
455
+ # # =>
456
+ # # shape: (1, 5)
457
+ # # ┌─────┬─────┬─────┬──────┬──────┐
458
+ # # │ key ┆ c00 ┆ c01 ┆ c98 ┆ c99 │
459
+ # # │ --- ┆ --- ┆ --- ┆ --- ┆ --- │
460
+ # # │ str ┆ f64 ┆ f64 ┆ f64 ┆ f64 │
461
+ # # ╞═════╪═════╪═════╪══════╪══════╡
462
+ # # │ abc ┆ 0.0 ┆ 0.5 ┆ 49.0 ┆ 49.5 │
463
+ # # └─────┴─────┴─────┴──────┴──────┘
464
+ #
465
+ # @example Select the "key" column and use a `range` object to select various columns.
466
+ # df.select(Polars.cs.by_index(0, (1...101).step(20)))
467
+ # # =>
468
+ # # shape: (1, 6)
469
+ # # ┌─────┬─────┬──────┬──────┬──────┬──────┐
470
+ # # │ key ┆ c00 ┆ c20 ┆ c40 ┆ c60 ┆ c80 │
471
+ # # │ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
472
+ # # │ str ┆ f64 ┆ f64 ┆ f64 ┆ f64 ┆ f64 │
473
+ # # ╞═════╪═════╪══════╪══════╪══════╪══════╡
474
+ # # │ abc ┆ 0.0 ┆ 10.0 ┆ 20.0 ┆ 30.0 ┆ 40.0 │
475
+ # # └─────┴─────┴──────┴──────┴──────┴──────┘
476
+ #
477
+ # @example
478
+ # df.select(Polars.cs.by_index(0, (101...0).step(-25), require_all: false))
479
+ # # =>
480
+ # # shape: (1, 5)
481
+ # # ┌─────┬──────┬──────┬──────┬─────┐
482
+ # # │ key ┆ c75 ┆ c50 ┆ c25 ┆ c00 │
483
+ # # │ --- ┆ --- ┆ --- ┆ --- ┆ --- │
484
+ # # │ str ┆ f64 ┆ f64 ┆ f64 ┆ f64 │
485
+ # # ╞═════╪══════╪══════╪══════╪═════╡
486
+ # # │ abc ┆ 37.5 ┆ 25.0 ┆ 12.5 ┆ 0.0 │
487
+ # # └─────┴──────┴──────┴──────┴─────┘
488
+ #
489
+ # @example Select all columns *except* for the even-indexed ones:
490
+ # df.select(~Polars.cs.by_index((1...100).step(2)))
491
+ # # =>
492
+ # # shape: (1, 51)
493
+ # # ┌─────┬─────┬─────┬─────┬───┬──────┬──────┬──────┬──────┐
494
+ # # │ key ┆ c01 ┆ c03 ┆ c05 ┆ … ┆ c93 ┆ c95 ┆ c97 ┆ c99 │
495
+ # # │ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ --- ┆ --- ┆ --- │
496
+ # # │ str ┆ f64 ┆ f64 ┆ f64 ┆ ┆ f64 ┆ f64 ┆ f64 ┆ f64 │
497
+ # # ╞═════╪═════╪═════╪═════╪═══╪══════╪══════╪══════╪══════╡
498
+ # # │ abc ┆ 0.5 ┆ 1.5 ┆ 2.5 ┆ … ┆ 46.5 ┆ 47.5 ┆ 48.5 ┆ 49.5 │
499
+ # # └─────┴─────┴─────┴─────┴───┴──────┴──────┴──────┴──────┘
500
+ def self.by_index(*indices, require_all: true)
501
+ all_indices = []
502
+ indices.each do |idx|
503
+ if idx.is_a?(Enumerable)
504
+ all_indices.concat(idx.to_a)
505
+ elsif idx.is_a?(Integer)
506
+ all_indices << idx
507
+ else
508
+ msg = "invalid index value: #{idx.inspect}"
509
+ raise TypeError, msg
510
+ end
511
+ end
512
+
513
+ Selector._from_rbselector(RbSelector.by_index(all_indices, require_all))
514
+ end
515
+
516
+ # Select all columns matching the given names.
517
+ #
518
+ # @param names [Array]
519
+ # One or more names of columns to select.
520
+ # @param require_all [Boolean]
521
+ # Whether to match *all* names (the default) or *any* of the names.
522
+ #
523
+ # @return [Selector]
524
+ #
525
+ # @note
526
+ # Matching columns are returned in the order in which they are declared in
527
+ # the selector, not the underlying schema order.
528
+ #
529
+ # @example
530
+ # df = Polars::DataFrame.new(
531
+ # {
532
+ # "foo" => ["x", "y"],
533
+ # "bar" => [123, 456],
534
+ # "baz" => [2.0, 5.5],
535
+ # "zap" => [false, true]
536
+ # }
537
+ # )
538
+ #
539
+ # @example Select columns by name:
540
+ # df.select(Polars.cs.by_name("foo", "bar"))
541
+ # # =>
542
+ # # shape: (2, 2)
543
+ # # ┌─────┬─────┐
544
+ # # │ foo ┆ bar │
545
+ # # │ --- ┆ --- │
546
+ # # │ str ┆ i64 │
547
+ # # ╞═════╪═════╡
548
+ # # │ x ┆ 123 │
549
+ # # │ y ┆ 456 │
550
+ # # └─────┴─────┘
551
+ #
552
+ # @example Match *any* of the given columns by name:
553
+ # df.select(Polars.cs.by_name("baz", "moose", "foo", "bear", require_all: false))
554
+ # # =>
555
+ # # shape: (2, 2)
556
+ # # ┌─────┬─────┐
557
+ # # │ baz ┆ foo │
558
+ # # │ --- ┆ --- │
559
+ # # │ f64 ┆ str │
560
+ # # ╞═════╪═════╡
561
+ # # │ 2.0 ┆ x │
562
+ # # │ 5.5 ┆ y │
563
+ # # └─────┴─────┘
564
+ #
565
+ # @example Match all columns *except* for those given:
566
+ # df.select(~Polars.cs.by_name("foo", "bar"))
567
+ # # =>
568
+ # # shape: (2, 2)
569
+ # # ┌─────┬───────┐
570
+ # # │ baz ┆ zap │
571
+ # # │ --- ┆ --- │
572
+ # # │ f64 ┆ bool │
573
+ # # ╞═════╪═══════╡
574
+ # # │ 2.0 ┆ false │
575
+ # # │ 5.5 ┆ true │
576
+ # # └─────┴───────┘
577
+ def self.by_name(*names, require_all: true)
578
+ all_names = []
579
+ names.each do |nm|
580
+ if nm.is_a?(::String)
581
+ all_names << nm
582
+ elsif nm.is_a?(::Array)
583
+ nm.each do |n|
584
+ if !n.is_a?(::String)
585
+ msg = "invalid name: #{n.inspect}"
586
+ raise TypeError, msg
587
+ end
588
+ all_names << n
589
+ end
590
+ else
591
+ msg = "invalid name: #{nm.inspect}"
592
+ raise TypeError, msg
593
+ end
594
+ end
595
+
596
+ Selector._by_name(all_names, strict: require_all, expand_patterns: false)
597
+ end
598
+
599
+ # Select all enum columns.
600
+ #
601
+ # @return [Selector]
602
+ #
603
+ # @note
604
+ # This functionality is considered **unstable**. It may be changed
605
+ # at any point without it being considered a breaking change.
606
+ #
607
+ # @example Select all enum columns:
608
+ # df = Polars::DataFrame.new(
609
+ # {
610
+ # "foo" => ["xx", "yy"],
611
+ # "bar" => [123, 456],
612
+ # "baz" => [2.0, 5.5],
613
+ # },
614
+ # schema_overrides: {"foo" => Polars::Enum.new(["xx", "yy"])}
615
+ # )
616
+ # df.select(Polars.cs.enum)
617
+ # # =>
618
+ # # shape: (2, 1)
619
+ # # ┌──────┐
620
+ # # │ foo │
621
+ # # │ --- │
622
+ # # │ enum │
623
+ # # ╞══════╡
624
+ # # │ xx │
625
+ # # │ yy │
626
+ # # └──────┘
627
+ #
628
+ # @example Select all columns *except* for those that are enum:
629
+ # df.select(~Polars.cs.enum)
630
+ # # =>
631
+ # # shape: (2, 2)
632
+ # # ┌─────┬─────┐
633
+ # # │ bar ┆ baz │
634
+ # # │ --- ┆ --- │
635
+ # # │ i64 ┆ f64 │
636
+ # # ╞═════╪═════╡
637
+ # # │ 123 ┆ 2.0 │
638
+ # # │ 456 ┆ 5.5 │
639
+ # # └─────┴─────┘
640
+ def self.enum
641
+ Selector._from_rbselector(RbSelector.enum_)
642
+ end
643
+
644
+ # Select all list columns.
645
+ #
646
+ # @return [Selector]
647
+ #
648
+ # @note
649
+ # This functionality is considered **unstable**. It may be changed
650
+ # at any point without it being considered a breaking change.
651
+ #
652
+ # @example Select all list columns:
653
+ # df = Polars::DataFrame.new(
654
+ # {
655
+ # "foo" => [["xx", "yy"], ["x"]],
656
+ # "bar" => [123, 456],
657
+ # "baz" => [2.0, 5.5]
658
+ # }
659
+ # )
660
+ # df.select(Polars.cs.list)
661
+ # # =>
662
+ # # shape: (2, 1)
663
+ # # ┌──────────────┐
664
+ # # │ foo │
665
+ # # │ --- │
666
+ # # │ list[str] │
667
+ # # ╞══════════════╡
668
+ # # │ ["xx", "yy"] │
669
+ # # │ ["x"] │
670
+ # # └──────────────┘
671
+ #
672
+ # @example Select all columns *except* for those that are list:
673
+ # df.select(~Polars.cs.list)
674
+ # # =>
675
+ # # shape: (2, 2)
676
+ # # ┌─────┬─────┐
677
+ # # │ bar ┆ baz │
678
+ # # │ --- ┆ --- │
679
+ # # │ i64 ┆ f64 │
680
+ # # ╞═════╪═════╡
681
+ # # │ 123 ┆ 2.0 │
682
+ # # │ 456 ┆ 5.5 │
683
+ # # └─────┴─────┘
684
+ #
685
+ # @example Select all list columns with a certain matching inner type:
686
+ # df.select(Polars.cs.list(Polars.cs.string))
687
+ # # =>
688
+ # # shape: (2, 1)
689
+ # # ┌──────────────┐
690
+ # # │ foo │
691
+ # # │ --- │
692
+ # # │ list[str] │
693
+ # # ╞══════════════╡
694
+ # # │ ["xx", "yy"] │
695
+ # # │ ["x"] │
696
+ # # └──────────────┘
697
+ #
698
+ # @example
699
+ # df.select(Polars.cs.list(Polars.cs.integer))
700
+ # # =>
701
+ # # shape: (0, 0)
702
+ # # ┌┐
703
+ # # ╞╡
704
+ # # └┘
705
+ def self.list(inner = nil)
706
+ inner_s = !inner.nil? ? inner._rbselector : nil
707
+ Selector._from_rbselector(RbSelector.list(inner_s))
708
+ end
709
+
710
+ # Select all array columns.
711
+ #
712
+ # @return [Selector]
713
+ #
714
+ # @note
715
+ # This functionality is considered **unstable**. It may be changed
716
+ # at any point without it being considered a breaking change.
717
+ #
718
+ # @example Select all array columns:
719
+ # df = Polars::DataFrame.new(
720
+ # {
721
+ # "foo" => [["xx", "yy"], ["x", "y"]],
722
+ # "bar" => [123, 456],
723
+ # "baz" => [2.0, 5.5]
724
+ # },
725
+ # schema_overrides: {"foo" => Polars::Array.new(Polars::String, 2)}
726
+ # )
727
+ # df.select(Polars.cs.array)
728
+ # # =>
729
+ # # shape: (2, 1)
730
+ # # ┌───────────────┐
731
+ # # │ foo │
732
+ # # │ --- │
733
+ # # │ array[str, 2] │
734
+ # # ╞═══════════════╡
735
+ # # │ ["xx", "yy"] │
736
+ # # │ ["x", "y"] │
737
+ # # └───────────────┘
738
+ #
739
+ # @example Select all columns *except* for those that are array:
740
+ # df.select(~Polars.cs.array)
741
+ # # =>
742
+ # # shape: (2, 2)
743
+ # # ┌─────┬─────┐
744
+ # # │ bar ┆ baz │
745
+ # # │ --- ┆ --- │
746
+ # # │ i64 ┆ f64 │
747
+ # # ╞═════╪═════╡
748
+ # # │ 123 ┆ 2.0 │
749
+ # # │ 456 ┆ 5.5 │
750
+ # # └─────┴─────┘
751
+ #
752
+ # @example Select all array columns with a certain matching inner type:
753
+ # df.select(Polars.cs.array(Polars.cs.string))
754
+ # # =>
755
+ # # shape: (2, 1)
756
+ # # ┌───────────────┐
757
+ # # │ foo │
758
+ # # │ --- │
759
+ # # │ array[str, 2] │
760
+ # # ╞═══════════════╡
761
+ # # │ ["xx", "yy"] │
762
+ # # │ ["x", "y"] │
763
+ # # └───────────────┘
764
+ #
765
+ # @example
766
+ # df.select(Polars.cs.array(Polars.cs.integer))
767
+ # # =>
768
+ # # shape: (0, 0)
769
+ # # ┌┐
770
+ # # ╞╡
771
+ # # └┘
772
+ #
773
+ # @example
774
+ # df.select(Polars.cs.array(width: 2))
775
+ # # =>
776
+ # # shape: (2, 1)
777
+ # # ┌───────────────┐
778
+ # # │ foo │
779
+ # # │ --- │
780
+ # # │ array[str, 2] │
781
+ # # ╞═══════════════╡
782
+ # # │ ["xx", "yy"] │
783
+ # # │ ["x", "y"] │
784
+ # # └───────────────┘
785
+ #
786
+ # @example
787
+ # df.select(Polars.cs.array(width: 3))
788
+ # # =>
789
+ # # shape: (0, 0)
790
+ # # ┌┐
791
+ # # ╞╡
792
+ # # └┘
793
+ def self.array(inner = nil, width: nil)
794
+ inner_s = !inner.nil? ? inner._rbselector : nil
795
+ Selector._from_rbselector(RbSelector.array(inner_s, width))
796
+ end
370
797
 
371
- # TODO
372
- # def by_index
373
- # end
798
+ # Select all struct columns.
799
+ #
800
+ # @return [Selector]
801
+ #
802
+ # @note
803
+ # This functionality is considered **unstable**. It may be changed
804
+ # at any point without it being considered a breaking change.
805
+ #
806
+ # @example Select all struct columns:
807
+ # df = Polars::DataFrame.new(
808
+ # {
809
+ # "foo" => [{"a" => "xx", "b" => "z"}, {"a" => "x", "b" => "y"}],
810
+ # "bar" => [123, 456],
811
+ # "baz" => [2.0, 5.5]
812
+ # }
813
+ # )
814
+ # df.select(Polars.cs.struct)
815
+ # # =>
816
+ # # shape: (2, 1)
817
+ # # ┌────────────┐
818
+ # # │ foo │
819
+ # # │ --- │
820
+ # # │ struct[2] │
821
+ # # ╞════════════╡
822
+ # # │ {"xx","z"} │
823
+ # # │ {"x","y"} │
824
+ # # └────────────┘
825
+ #
826
+ # @example Select all columns *except* for those that are struct:
827
+ # df.select(~Polars.cs.struct)
828
+ # # =>
829
+ # # shape: (2, 2)
830
+ # # ┌─────┬─────┐
831
+ # # │ bar ┆ baz │
832
+ # # │ --- ┆ --- │
833
+ # # │ i64 ┆ f64 │
834
+ # # ╞═════╪═════╡
835
+ # # │ 123 ┆ 2.0 │
836
+ # # │ 456 ┆ 5.5 │
837
+ # # └─────┴─────┘
838
+ def self.struct
839
+ Selector._from_rbselector(RbSelector.struct_)
840
+ end
374
841
 
375
- # TODO
376
- # def by_name
377
- # end
842
+ # Select all nested columns.
843
+ #
844
+ # A nested column is a list, array or struct.
845
+ #
846
+ # @return [Selector]
847
+ #
848
+ # @note
849
+ # This functionality is considered **unstable**. It may be changed
850
+ # at any point without it being considered a breaking change.
851
+ #
852
+ # @example Select all nested columns:
853
+ # df = Polars::DataFrame.new(
854
+ # {
855
+ # "foo" => [{"a" => "xx", "b" => "z"}, {"a" => "x", "b" => "y"}],
856
+ # "bar" => [123, 456],
857
+ # "baz" => [2.0, 5.5],
858
+ # "wow" => [[1, 2], [3]]
859
+ # }
860
+ # )
861
+ # df.select(Polars.cs.nested)
862
+ # # =>
863
+ # # shape: (2, 2)
864
+ # # ┌────────────┬───────────┐
865
+ # # │ foo ┆ wow │
866
+ # # │ --- ┆ --- │
867
+ # # │ struct[2] ┆ list[i64] │
868
+ # # ╞════════════╪═══════════╡
869
+ # # │ {"xx","z"} ┆ [1, 2] │
870
+ # # │ {"x","y"} ┆ [3] │
871
+ # # └────────────┴───────────┘
872
+ #
873
+ # @example Select all columns *except* for those that are nested:
874
+ # df.select(~Polars.cs.nested)
875
+ # # =>
876
+ # # shape: (2, 2)
877
+ # # ┌─────┬─────┐
878
+ # # │ bar ┆ baz │
879
+ # # │ --- ┆ --- │
880
+ # # │ i64 ┆ f64 │
881
+ # # ╞═════╪═════╡
882
+ # # │ 123 ┆ 2.0 │
883
+ # # │ 456 ┆ 5.5 │
884
+ # # └─────┴─────┘
885
+ def self.nested
886
+ Selector._from_rbselector(RbSelector.nested)
887
+ end
378
888
 
379
889
  # Select all categorical columns.
380
890
  #
381
- # @return [SelectorProxy]
891
+ # @return [Selector]
382
892
  #
383
893
  # @example
384
894
  # df = Polars::DataFrame.new(
@@ -416,7 +926,7 @@ module Polars
416
926
  # # │ 456 ┆ 5.5 │
417
927
  # # └─────┴─────┘
418
928
  def self.categorical
419
- _selector_proxy_(F.col(Categorical), name: "categorical")
929
+ Selector._from_rbselector(RbSelector.categorical)
420
930
  end
421
931
 
422
932
  # Select columns whose names contain the given literal substring(s).
@@ -424,7 +934,7 @@ module Polars
424
934
  # @param substring [Object]
425
935
  # Substring(s) that matching column names should contain.
426
936
  #
427
- # @return [SelectorProxy]
937
+ # @return [Selector]
428
938
  #
429
939
  # @example
430
940
  # df = Polars::DataFrame.new(
@@ -478,16 +988,12 @@ module Polars
478
988
  escaped_substring = _re_string(substring)
479
989
  raw_params = "^.*#{escaped_substring}.*$"
480
990
 
481
- _selector_proxy_(
482
- F.col(raw_params),
483
- name: "contains",
484
- parameters: {"*substring" => escaped_substring}
485
- )
991
+ Selector._from_rbselector(RbSelector.matches(raw_params))
486
992
  end
487
993
 
488
994
  # Select all date columns.
489
995
  #
490
- # @return [SelectorProxy]
996
+ # @return [Selector]
491
997
  #
492
998
  # @example
493
999
  # df = Polars::DataFrame.new(
@@ -523,16 +1029,41 @@ module Polars
523
1029
  # # │ 2031-12-31 00:30:00 │
524
1030
  # # └─────────────────────┘
525
1031
  def self.date
526
- _selector_proxy_(F.col(Date), name: "date")
1032
+ by_dtype([Date])
527
1033
  end
528
1034
 
529
- # TODO
530
- # def datetime
531
- # end
1035
+ # Select all datetime columns, optionally filtering by time unit/zone.
1036
+ #
1037
+ # @param time_unit ['ms', 'us', 'ns']
1038
+ # One (or more) of the allowed timeunit precision strings, "ms", "us", and "ns".
1039
+ # Omit to select columns with any valid timeunit.
1040
+ # @param time_zone [String]
1041
+ # * One or more timezone strings, as defined in zoneinfo (to see valid options
1042
+ # run `import zoneinfo; zoneinfo.available_timezones()` for a full list).
1043
+ # * Set `nil` to select Datetime columns that do not have a timezone.
1044
+ # * Set "*" to select Datetime columns that have *any* timezone.
1045
+ #
1046
+ # @return [Selector]
1047
+ def self.datetime(time_unit = nil, time_zone: ["*", nil])
1048
+ if time_unit.nil?
1049
+ time_unit_lst = ["ms", "us", "ns"]
1050
+ else
1051
+ time_unit_lst = time_unit.is_a?(::String) ? [time_unit] : time_unit.to_a
1052
+ end
1053
+
1054
+ if time_zone.nil?
1055
+ time_zone_lst = [nil]
1056
+ elsif time_zone
1057
+ # TODO improve
1058
+ time_zone_lst = time_zone.to_a
1059
+ end
1060
+
1061
+ Selector._from_rbselector(RbSelector.datetime(time_unit_lst, time_zone_lst))
1062
+ end
532
1063
 
533
1064
  # Select all decimal columns.
534
1065
  #
535
- # @return [SelectorProxy]
1066
+ # @return [Selector]
536
1067
  #
537
1068
  # @example
538
1069
  # df = Polars::DataFrame.new(
@@ -548,14 +1079,14 @@ module Polars
548
1079
  # df.select(Polars.cs.decimal)
549
1080
  # # =>
550
1081
  # # shape: (2, 2)
551
- # # ┌──────────────┬───────────────┐
552
- # # │ bar ┆ baz │
553
- # # │ --- ┆ --- │
554
- # # │ decimal[*,0] ┆ decimal[10,5] │
555
- # # ╞══════════════╪═══════════════╡
556
- # # │ 123 ┆ 2.00050 │
557
- # # │ 456 ┆ -50.55550 │
558
- # # └──────────────┴───────────────┘
1082
+ # # ┌───────────────┬───────────────┐
1083
+ # # │ bar ┆ baz │
1084
+ # # │ --- ┆ --- │
1085
+ # # │ decimal[38,0] ┆ decimal[10,5] │
1086
+ # # ╞═══════════════╪═══════════════╡
1087
+ # # │ 123 ┆ 2.00050 │
1088
+ # # │ 456 ┆ -50.55550 │
1089
+ # # └───────────────┴───────────────┘
559
1090
  #
560
1091
  # @example Select all columns *except* the decimal ones:
561
1092
  #
@@ -572,7 +1103,112 @@ module Polars
572
1103
  # # └─────┘
573
1104
  def self.decimal
574
1105
  # TODO: allow explicit selection by scale/precision?
575
- _selector_proxy_(F.col(Decimal), name: "decimal")
1106
+ Selector._from_rbselector(RbSelector.decimal)
1107
+ end
1108
+
1109
+ # Select all columns having names consisting only of digits.
1110
+ #
1111
+ # @return [Selector]
1112
+ #
1113
+ # @note
1114
+ # Matching column names cannot contain *any* non-digit characters. Note that the
1115
+ # definition of "digit" consists of all valid Unicode digit characters (`\d`)
1116
+ # by default; this can be changed by setting `ascii_only: true`.
1117
+ #
1118
+ # @example
1119
+ # df = Polars::DataFrame.new(
1120
+ # {
1121
+ # "key" => ["aaa", "bbb", "aaa", "bbb", "bbb"],
1122
+ # "year" => [2001, 2001, 2025, 2025, 2001],
1123
+ # "value" => [-25, 100, 75, -15, -5]
1124
+ # }
1125
+ # ).pivot(
1126
+ # "year",
1127
+ # values: "value",
1128
+ # index: "key",
1129
+ # aggregate_function: "sum"
1130
+ # )
1131
+ # # =>
1132
+ # # shape: (2, 3)
1133
+ # # ┌─────┬──────┬──────┐
1134
+ # # │ key ┆ 2001 ┆ 2025 │
1135
+ # # │ --- ┆ --- ┆ --- │
1136
+ # # │ str ┆ i64 ┆ i64 │
1137
+ # # ╞═════╪══════╪══════╡
1138
+ # # │ aaa ┆ -25 ┆ 75 │
1139
+ # # │ bbb ┆ 95 ┆ -15 │
1140
+ # # └─────┴──────┴──────┘
1141
+ #
1142
+ # @example Select columns with digit names:
1143
+ # df.select(Polars.cs.digit)
1144
+ # # =>
1145
+ # # shape: (2, 2)
1146
+ # # ┌──────┬──────┐
1147
+ # # │ 2001 ┆ 2025 │
1148
+ # # │ --- ┆ --- │
1149
+ # # │ i64 ┆ i64 │
1150
+ # # ╞══════╪══════╡
1151
+ # # │ -25 ┆ 75 │
1152
+ # # │ 95 ┆ -15 │
1153
+ # # └──────┴──────┘
1154
+ #
1155
+ # @example Select all columns *except* for those with digit names:
1156
+ # df.select(~Polars.cs.digit)
1157
+ # # =>
1158
+ # # shape: (2, 1)
1159
+ # # ┌─────┐
1160
+ # # │ key │
1161
+ # # │ --- │
1162
+ # # │ str │
1163
+ # # ╞═════╡
1164
+ # # │ aaa │
1165
+ # # │ bbb │
1166
+ # # └─────┘
1167
+ #
1168
+ # @example Demonstrate use of `ascii_only` flag (by default all valid unicode digits are considered, but this can be constrained to ascii 0-9):
1169
+ # df = Polars::DataFrame.new({"१९९९" => [1999], "२०७७" => [2077], "3000": [3000]})
1170
+ # df.select(Polars.cs.digit)
1171
+ # # =>
1172
+ # # shape: (1, 3)
1173
+ # # ┌──────┬──────┬──────┐
1174
+ # # │ १९९९ ┆ २०७७ ┆ 3000 │
1175
+ # # │ --- ┆ --- ┆ --- │
1176
+ # # │ i64 ┆ i64 ┆ i64 │
1177
+ # # ╞══════╪══════╪══════╡
1178
+ # # │ 1999 ┆ 2077 ┆ 3000 │
1179
+ # # └──────┴──────┴──────┘
1180
+ #
1181
+ # @example
1182
+ # df.select(Polars.cs.digit(ascii_only: true))
1183
+ # # =>
1184
+ # # shape: (1, 1)
1185
+ # # ┌──────┐
1186
+ # # │ 3000 │
1187
+ # # │ --- │
1188
+ # # │ i64 │
1189
+ # # ╞══════╡
1190
+ # # │ 3000 │
1191
+ # # └──────┘
1192
+ def self.digit(ascii_only: false)
1193
+ re_digit = ascii_only ? "[0-9]" : "\\d"
1194
+ Selector._from_rbselector(RbSelector.matches("^#{re_digit}+$"))
1195
+ end
1196
+
1197
+ # Select all duration columns, optionally filtering by time unit.
1198
+ #
1199
+ # @param time_unit ['ms', 'us', 'ns']
1200
+ # One (or more) of the allowed timeunit precision strings, "ms", "us", and "ns".
1201
+ # Omit to select columns with any valid timeunit.
1202
+ #
1203
+ # @return [Selector]
1204
+ def self.duration(time_unit = nil)
1205
+ if time_unit.nil?
1206
+ time_unit = ["ms", "us", "ns"]
1207
+ else
1208
+ time_unit = time_unit.is_a?(::String) ? [time_unit] : time_unit.to_a
1209
+ end
1210
+
1211
+ Selector._from_rbselector(RbSelector.duration(time_unit))
576
1212
  end
577
1213
 
578
1214
  # Select columns that end with the given substring(s).
@@ -580,7 +1216,7 @@ module Polars
580
1216
  # @param suffix [Object]
581
1217
  # Substring(s) that matching column names should end with.
582
1218
  #
583
- # @return [SelectorProxy]
1219
+ # @return [Selector]
584
1220
  #
585
1221
  # @example
586
1222
  # df = Polars::DataFrame.new(
@@ -634,16 +1270,64 @@ module Polars
634
1270
  escaped_suffix = _re_string(suffix)
635
1271
  raw_params = "^.*#{escaped_suffix}$"
636
1272
 
637
- _selector_proxy_(
638
- F.col(raw_params),
639
- name: "ends_with",
640
- parameters: {"*suffix" => escaped_suffix},
641
- )
1273
+ Selector._from_rbselector(RbSelector.matches(raw_params))
1274
+ end
1275
+
1276
+ # Select all columns except those matching the given columns, datatypes, or selectors.
1277
+ #
1278
+ # @param columns [Object]
1279
+ # One or more columns (col or name), datatypes, columns, or selectors representing
1280
+ # the columns to exclude.
1281
+ # @param more_columns [Array]
1282
+ # Additional columns, datatypes, or selectors to exclude, specified as positional
1283
+ # arguments.
1284
+ #
1285
+ # @return [Selector]
1286
+ #
1287
+ # @note
1288
+ # If excluding a single selector it is simpler to write as `~selector` instead.
1289
+ #
1290
+ # @example Exclude by column name(s):
1291
+ # df = Polars::DataFrame.new(
1292
+ # {
1293
+ # "aa" => [1, 2, 3],
1294
+ # "ba" => ["a", "b", nil],
1295
+ # "cc" => [nil, 2.5, 1.5]
1296
+ # }
1297
+ # )
1298
+ # df.select(Polars.cs.exclude("ba", "xx"))
1299
+ # # =>
1300
+ # # shape: (3, 2)
1301
+ # # ┌─────┬──────┐
1302
+ # # │ aa ┆ cc │
1303
+ # # │ --- ┆ --- │
1304
+ # # │ i64 ┆ f64 │
1305
+ # # ╞═════╪══════╡
1306
+ # # │ 1 ┆ null │
1307
+ # # │ 2 ┆ 2.5 │
1308
+ # # │ 3 ┆ 1.5 │
1309
+ # # └─────┴──────┘
1310
+ #
1311
+ # @example Exclude using a column name, a selector, and a dtype:
1312
+ # df.select(Polars.cs.exclude("aa", Polars.cs.string, Polars::UInt32))
1313
+ # # =>
1314
+ # # shape: (3, 1)
1315
+ # # ┌──────┐
1316
+ # # │ cc │
1317
+ # # │ --- │
1318
+ # # │ f64 │
1319
+ # # ╞══════╡
1320
+ # # │ null │
1321
+ # # │ 2.5 │
1322
+ # # │ 1.5 │
1323
+ # # └──────┘
1324
+ def self.exclude(columns, *more_columns)
1325
+ ~_combine_as_selector(columns, *more_columns)
642
1326
  end
643
1327
 
644
1328
  # Select the first column in the current scope.
645
1329
  #
646
- # @return [SelectorProxy]
1330
+ # @return [Selector]
647
1331
  #
648
1332
  # @example
649
1333
  # df = Polars::DataFrame.new(
@@ -680,13 +1364,13 @@ module Polars
680
1364
  # # │ 123 ┆ 2.0 ┆ 0 │
681
1365
  # # │ 456 ┆ 5.5 ┆ 1 │
682
1366
  # # └─────┴─────┴─────┘
683
- def self.first
684
- _selector_proxy_(F.first, name: "first")
1367
+ def self.first(strict: true)
1368
+ Selector._from_rbselector(RbSelector.first(strict))
685
1369
  end
686
1370
 
687
1371
  # Select all float columns.
688
1372
  #
689
- # @return [SelectorProxy]
1373
+ # @return [Selector]
690
1374
  #
691
1375
  # @example
692
1376
  # df = Polars::DataFrame.new(
@@ -725,12 +1409,12 @@ module Polars
725
1409
  # # │ y ┆ 456 │
726
1410
  # # └─────┴─────┘
727
1411
  def self.float
728
- _selector_proxy_(F.col(FLOAT_DTYPES), name: "float")
1412
+ Selector._from_rbselector(RbSelector.float)
729
1413
  end
730
1414
 
731
1415
  # Select all integer columns.
732
1416
  #
733
- # @return [SelectorProxy]
1417
+ # @return [Selector]
734
1418
  #
735
1419
  # @example
736
1420
  # df = Polars::DataFrame.new(
@@ -768,12 +1452,12 @@ module Polars
768
1452
  # # │ y ┆ 5.5 │
769
1453
  # # └─────┴─────┘
770
1454
  def self.integer
771
- _selector_proxy_(F.col(INTEGER_DTYPES), name: "integer")
1455
+ Selector._from_rbselector(RbSelector.integer)
772
1456
  end
773
1457
 
774
1458
  # Select all signed integer columns.
775
1459
  #
776
- # @return [SelectorProxy]
1460
+ # @return [Selector]
777
1461
  #
778
1462
  # @example
779
1463
  # df = Polars::DataFrame.new(
@@ -825,12 +1509,12 @@ module Polars
825
1509
  # # │ -456 ┆ 6789 ┆ 4321 │
826
1510
  # # └──────┴──────┴──────┘
827
1511
  def self.signed_integer
828
- _selector_proxy_(F.col(SIGNED_INTEGER_DTYPES), name: "signed_integer")
1512
+ Selector._from_rbselector(RbSelector.signed_integer)
829
1513
  end
830
1514
 
831
1515
  # Select all unsigned integer columns.
832
1516
  #
833
- # @return [SelectorProxy]
1517
+ # @return [Selector]
834
1518
  #
835
1519
  # @example
836
1520
  # df = Polars::DataFrame.new(
@@ -882,12 +1566,12 @@ module Polars
882
1566
  # # │ -456 ┆ 6789 ┆ 4321 │
883
1567
  # # └──────┴──────┴──────┘
884
1568
  def self.unsigned_integer
885
- _selector_proxy_(F.col(UNSIGNED_INTEGER_DTYPES), name: "unsigned_integer")
1569
+ Selector._from_rbselector(RbSelector.unsigned_integer)
886
1570
  end
887
1571
 
888
1572
  # Select the last column in the current scope.
889
1573
  #
890
- # @return [SelectorProxy]
1574
+ # @return [Selector]
891
1575
  #
892
1576
  # @example
893
1577
  # df = Polars::DataFrame.new(
@@ -924,13 +1608,71 @@ module Polars
924
1608
  # # │ x ┆ 123 ┆ 2.0 │
925
1609
  # # │ y ┆ 456 ┆ 5.5 │
926
1610
  # # └─────┴─────┴─────┘
927
- def self.last
928
- _selector_proxy_(F.last, name: "last")
1611
+ def self.last(strict: true)
1612
+ Selector._from_rbselector(RbSelector.last(strict))
1613
+ end
1614
+
1615
+ # Select all columns that match the given regex pattern.
1616
+ #
1617
+ # @param pattern [String]
1618
+ # A valid regular expression pattern, compatible with the [regex crate](https://docs.rs/regex/latest/regex/).
1619
+ #
1620
+ # @return [Selector]
1621
+ #
1622
+ # @example Match column names containing an 'a', preceded by a character that is not 'z':
1623
+ # df = Polars::DataFrame.new(
1624
+ # {
1625
+ # "foo" => ["x", "y"],
1626
+ # "bar" => [123, 456],
1627
+ # "baz" => [2.0, 5.5],
1628
+ # "zap" => [0, 1]
1629
+ # }
1630
+ # )
1631
+ # df.select(Polars.cs.matches("[^z]a"))
1632
+ # # =>
1633
+ # # shape: (2, 2)
1634
+ # # ┌─────┬─────┐
1635
+ # # │ bar ┆ baz │
1636
+ # # │ --- ┆ --- │
1637
+ # # │ i64 ┆ f64 │
1638
+ # # ╞═════╪═════╡
1639
+ # # │ 123 ┆ 2.0 │
1640
+ # # │ 456 ┆ 5.5 │
1641
+ # # └─────┴─────┘
1642
+ #
1643
+ # @example Do not match column names ending in 'R' or 'z' (case-insensitively):
1644
+ # df.select(~Polars.cs.matches("(?i)R|z$"))
1645
+ # # =>
1646
+ # # shape: (2, 2)
1647
+ # # ┌─────┬─────┐
1648
+ # # │ foo ┆ zap │
1649
+ # # │ --- ┆ --- │
1650
+ # # │ str ┆ i64 │
1651
+ # # ╞═════╪═════╡
1652
+ # # │ x ┆ 0 │
1653
+ # # │ y ┆ 1 │
1654
+ # # └─────┴─────┘
1655
+ def self.matches(pattern)
1656
+ if pattern == ".*"
1657
+ all
1658
+ else
1659
+ if pattern.start_with?(".*")
1660
+ pattern = pattern[2..]
1661
+ elsif pattern.end_with?(".*")
1662
+ pattern = pattern[..-3]
1663
+ end
1664
+
1665
+ pfx = !pattern.start_with?("^") ? "^.*" : ""
1666
+ sfx = !pattern.end_with?("$") ? ".*$" : ""
1667
+ raw_params = "#{pfx}#{pattern}#{sfx}"
1668
+
1669
+ Selector._from_rbselector(RbSelector.matches(raw_params))
1670
+ end
929
1671
  end
930
1672
 
931
1673
  # Select all numeric columns.
932
1674
  #
933
- # @return [SelectorProxy]
1675
+ # @return [Selector]
934
1676
  #
935
1677
  # @example
936
1678
  # df = Polars::DataFrame.new(
@@ -969,7 +1711,26 @@ module Polars
969
1711
  # # │ y │
970
1712
  # # └─────┘
971
1713
  def self.numeric
972
- _selector_proxy_(F.col(NUMERIC_DTYPES), name: "numeric")
1714
+ Selector._from_rbselector(RbSelector.numeric)
1715
+ end
1716
+
1717
+ # Select all object columns.
1718
+ #
1719
+ # @return [Selector]
1720
+ #
1721
+ # @example
1722
+ # df = Polars::DataFrame.new(
1723
+ # {
1724
+ # "idx" => [0, 1],
1725
+ # "uuid_obj" => ["6be063cf-c9c6-43be-878e-e446cfd42981", "7849d8f9-2cac-48e7-96d3-63cf81c14869"],
1726
+ # "uuid_str" => ["acab9fea-c05d-4b91-b639-418004a63f33", "28c65415-8b7d-4857-a4ce-300dca14b12b"]
1727
+ # },
1728
+ # schema_overrides: {"idx" => Polars::Int32, "uuid_obj" => Polars::Object}
1729
+ # )
1730
+ # df.select(Polars.cs.object).to_h(as_series: false)
1731
+ # # => {"uuid_obj"=>["6be063cf-c9c6-43be-878e-e446cfd42981", "7849d8f9-2cac-48e7-96d3-63cf81c14869"]}
1732
+ def self.object
1733
+ Selector._from_rbselector(RbSelector.object)
973
1734
  end
974
1735
 
975
1736
  # Select columns that start with the given substring(s).
@@ -977,7 +1738,7 @@ module Polars
977
1738
  # @param prefix [Object]
978
1739
  # Substring(s) that matching column names should start with.
979
1740
  #
980
- # @return [SelectorProxy]
1741
+ # @return [Selector]
981
1742
  #
982
1743
  # @example
983
1744
  # df = Polars::DataFrame.new(
@@ -1031,16 +1792,12 @@ module Polars
1031
1792
  escaped_prefix = _re_string(prefix)
1032
1793
  raw_params = "^#{escaped_prefix}.*$"
1033
1794
 
1034
- _selector_proxy_(
1035
- F.col(raw_params),
1036
- name: "starts_with",
1037
- parameters: {"*prefix" => prefix}
1038
- )
1795
+ Selector._from_rbselector(RbSelector.matches(raw_params))
1039
1796
  end
1040
1797
 
1041
1798
  # Select all String (and, optionally, Categorical) string columns.
1042
1799
  #
1043
- # @return [SelectorProxy]
1800
+ # @return [Selector]
1044
1801
  #
1045
1802
  # @example
1046
1803
  # df = Polars::DataFrame.new(
@@ -1087,16 +1844,66 @@ module Polars
1087
1844
  string_dtypes << Categorical
1088
1845
  end
1089
1846
 
1090
- _selector_proxy_(
1091
- F.col(string_dtypes),
1092
- name: "string",
1093
- parameters: {"include_categorical" => include_categorical},
1094
- )
1847
+ by_dtype(string_dtypes)
1848
+ end
1849
+
1850
+ # Select all temporal columns.
1851
+ #
1852
+ # @return [Selector]
1853
+ #
1854
+ # @example Match all temporal columns:
1855
+ # df = Polars::DataFrame.new(
1856
+ # {
1857
+ # "dt" => [Date.new(2021, 1, 1), Date.new(2021, 1, 2)],
1858
+ # "tm" => [DateTime.new(2000, 1, 1, 12, 0, 0), DateTime.new(2000, 1, 1, 20, 30, 45)],
1859
+ # "value" => [1.2345, 2.3456],
1860
+ # },
1861
+ # schema_overrides: {"tm" => Polars::Time}
1862
+ # )
1863
+ # df.select(Polars.cs.temporal)
1864
+ # # =>
1865
+ # # shape: (2, 2)
1866
+ # # ┌────────────┬──────────┐
1867
+ # # │ dt ┆ tm │
1868
+ # # │ --- ┆ --- │
1869
+ # # │ date ┆ time │
1870
+ # # ╞════════════╪══════════╡
1871
+ # # │ 2021-01-01 ┆ 12:00:00 │
1872
+ # # │ 2021-01-02 ┆ 20:30:45 │
1873
+ # # └────────────┴──────────┘
1874
+ #
1875
+ # @example Match all temporal columns *except* for time columns:
1876
+ # df.select(Polars.cs.temporal - Polars.cs.time)
1877
+ # # =>
1878
+ # # shape: (2, 1)
1879
+ # # ┌────────────┐
1880
+ # # │ dt │
1881
+ # # │ --- │
1882
+ # # │ date │
1883
+ # # ╞════════════╡
1884
+ # # │ 2021-01-01 │
1885
+ # # │ 2021-01-02 │
1886
+ # # └────────────┘
1887
+ #
1888
+ # @example Match all columns *except* for temporal columns:
1889
+ # df.select(~Polars.cs.temporal)
1890
+ # # =>
1891
+ # # shape: (2, 1)
1892
+ # # ┌────────┐
1893
+ # # │ value │
1894
+ # # │ --- │
1895
+ # # │ f64 │
1896
+ # # ╞════════╡
1897
+ # # │ 1.2345 │
1898
+ # # │ 2.3456 │
1899
+ # # └────────┘
1900
+ def self.temporal
1901
+ Selector._from_rbselector(RbSelector.temporal)
1095
1902
  end
1096
1903
 
1097
1904
  # Select all time columns.
1098
1905
  #
1099
- # @return [SelectorProxy]
1906
+ # @return [Selector]
1100
1907
  #
1101
1908
  # @example
1102
1909
  # df = Polars::DataFrame.new(
@@ -1134,11 +1941,51 @@ module Polars
1134
1941
  # # │ 2031-12-31 00:30:00 ┆ 2024-08-09 │
1135
1942
  # # └─────────────────────┴────────────┘
1136
1943
  def self.time
1137
- _selector_proxy_(F.col(Time), name: "time")
1944
+ by_dtype([Time])
1945
+ end
1946
+
1947
+ # @private
1948
+ def self._combine_as_selector(items, *more_items)
1949
+ names, regexes, dtypes = [], [], []
1950
+ selectors = []
1951
+ ((items.is_a?(::Array) ? items : [items]) + more_items).each do |item|
1952
+ if Utils.is_selector(item)
1953
+ selectors << item
1954
+ elsif item.is_a?(::String)
1955
+ if item.start_with?("^") && item.end_with?("$")
1956
+ regexes << item
1957
+ else
1958
+ names << item
1959
+ end
1960
+ elsif Utils.is_polars_dtype(item)
1961
+ dtypes << item
1962
+ elsif Utils.is_column(item)
1963
+ names << item.meta.output_name
1964
+ else
1965
+ msg = "expected one or more `str`, `DataType` or selector; found #{item.inspect} instead."
1966
+ raise TypeError, msg
1967
+ end
1968
+ end
1969
+
1970
+ selected = []
1971
+ if names.any?
1972
+ selected << by_name(*names, require_all: false)
1973
+ end
1974
+ if dtypes.any?
1975
+ selected << by_dtype(*dtypes)
1976
+ end
1977
+ if regexes.any?
1978
+ raise Todo
1979
+ end
1980
+ if selectors.any?
1981
+ selected.concat(selectors)
1982
+ end
1983
+
1984
+ selected.reduce(empty, :|)
1138
1985
  end
1139
1986
  end
1140
1987
 
1141
1988
  def self.cs
1142
- Polars::Selectors
1989
+ Selectors
1143
1990
  end
1144
1991
  end