polars-df 0.21.0 → 0.21.1

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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -0
  3. data/Cargo.lock +1 -1
  4. data/ext/polars/Cargo.toml +7 -1
  5. data/ext/polars/src/conversion/mod.rs +92 -4
  6. data/ext/polars/src/exceptions.rs +1 -0
  7. data/ext/polars/src/expr/array.rs +73 -4
  8. data/ext/polars/src/expr/binary.rs +26 -1
  9. data/ext/polars/src/expr/bitwise.rs +39 -0
  10. data/ext/polars/src/expr/categorical.rs +20 -0
  11. data/ext/polars/src/expr/datatype.rs +24 -1
  12. data/ext/polars/src/expr/datetime.rs +58 -0
  13. data/ext/polars/src/expr/general.rs +84 -5
  14. data/ext/polars/src/expr/list.rs +24 -0
  15. data/ext/polars/src/expr/meta.rs +11 -0
  16. data/ext/polars/src/expr/mod.rs +1 -0
  17. data/ext/polars/src/expr/name.rs +8 -0
  18. data/ext/polars/src/expr/rolling.rs +20 -0
  19. data/ext/polars/src/expr/string.rs +59 -0
  20. data/ext/polars/src/expr/struct.rs +9 -1
  21. data/ext/polars/src/functions/io.rs +19 -0
  22. data/ext/polars/src/functions/lazy.rs +4 -0
  23. data/ext/polars/src/lazyframe/general.rs +51 -0
  24. data/ext/polars/src/lib.rs +119 -10
  25. data/ext/polars/src/map/dataframe.rs +2 -2
  26. data/ext/polars/src/map/series.rs +1 -1
  27. data/ext/polars/src/series/aggregation.rs +44 -0
  28. data/ext/polars/src/series/general.rs +64 -4
  29. data/lib/polars/array_expr.rb +382 -3
  30. data/lib/polars/array_name_space.rb +281 -0
  31. data/lib/polars/binary_expr.rb +67 -0
  32. data/lib/polars/binary_name_space.rb +43 -0
  33. data/lib/polars/cat_expr.rb +224 -0
  34. data/lib/polars/cat_name_space.rb +138 -0
  35. data/lib/polars/config.rb +2 -2
  36. data/lib/polars/convert.rb +6 -6
  37. data/lib/polars/data_frame.rb +684 -19
  38. data/lib/polars/data_type_expr.rb +52 -0
  39. data/lib/polars/data_types.rb +14 -2
  40. data/lib/polars/date_time_expr.rb +251 -0
  41. data/lib/polars/date_time_name_space.rb +299 -0
  42. data/lib/polars/expr.rb +1213 -180
  43. data/lib/polars/functions/datatype.rb +21 -0
  44. data/lib/polars/functions/lazy.rb +13 -0
  45. data/lib/polars/io/csv.rb +1 -1
  46. data/lib/polars/io/json.rb +4 -4
  47. data/lib/polars/io/ndjson.rb +4 -4
  48. data/lib/polars/io/parquet.rb +27 -5
  49. data/lib/polars/lazy_frame.rb +936 -20
  50. data/lib/polars/list_expr.rb +196 -4
  51. data/lib/polars/list_name_space.rb +201 -4
  52. data/lib/polars/meta_expr.rb +64 -0
  53. data/lib/polars/name_expr.rb +36 -0
  54. data/lib/polars/schema.rb +79 -3
  55. data/lib/polars/selector.rb +72 -0
  56. data/lib/polars/selectors.rb +3 -3
  57. data/lib/polars/series.rb +1051 -54
  58. data/lib/polars/string_expr.rb +411 -6
  59. data/lib/polars/string_name_space.rb +722 -49
  60. data/lib/polars/struct_expr.rb +103 -0
  61. data/lib/polars/struct_name_space.rb +19 -1
  62. data/lib/polars/utils/various.rb +18 -1
  63. data/lib/polars/utils.rb +5 -1
  64. data/lib/polars/version.rb +1 -1
  65. data/lib/polars.rb +2 -0
  66. metadata +4 -1
@@ -368,6 +368,71 @@ module Polars
368
368
  end
369
369
  alias_method :concat, :join
370
370
 
371
+ # Returns string values with all regular expression meta characters escaped.
372
+ #
373
+ # @return [Expr]
374
+ #
375
+ # @example
376
+ # df = Polars::DataFrame.new({"text" => ["abc", "def", nil, "abc(\\w+)"]})
377
+ # df.with_columns(Polars.col("text").str.escape_regex.alias("escaped"))
378
+ # # =>
379
+ # # shape: (4, 2)
380
+ # # ┌──────────┬──────────────┐
381
+ # # │ text ┆ escaped │
382
+ # # │ --- ┆ --- │
383
+ # # │ str ┆ str │
384
+ # # ╞══════════╪══════════════╡
385
+ # # │ abc ┆ abc │
386
+ # # │ def ┆ def │
387
+ # # │ null ┆ null │
388
+ # # │ abc(\w+) ┆ abc\(\\w\+\) │
389
+ # # └──────────┴──────────────┘
390
+ def escape_regex
391
+ Utils.wrap_expr(_rbexpr.str_escape_regex)
392
+ end
393
+
394
+ # Returns the Unicode normal form of the string values.
395
+ #
396
+ # This uses the forms described in Unicode Standard Annex 15: <https://www.unicode.org/reports/tr15/>.
397
+ #
398
+ # @param form ['NFC', 'NFKC', 'NFD', 'NFKD']
399
+ # Unicode form to use.
400
+ #
401
+ # @return [Expr]
402
+ #
403
+ # @example
404
+ # df = Polars::DataFrame.new({"text" => ["01²", "KADOKAWA"]})
405
+ # new = df.with_columns(
406
+ # nfc: Polars.col("text").str.normalize("NFC"),
407
+ # nfkc: Polars.col("text").str.normalize("NFKC")
408
+ # )
409
+ # # =>
410
+ # # shape: (2, 3)
411
+ # # ┌──────────────────┬──────────────────┬──────────┐
412
+ # # │ text ┆ nfc ┆ nfkc │
413
+ # # │ --- ┆ --- ┆ --- │
414
+ # # │ str ┆ str ┆ str │
415
+ # # ╞══════════════════╪══════════════════╪══════════╡
416
+ # # │ 01² ┆ 01² ┆ 012 │
417
+ # # │ KADOKAWA ┆ KADOKAWA ┆ KADOKAWA │
418
+ # # └──────────────────┴──────────────────┴──────────┘
419
+ #
420
+ # @example
421
+ # new.select(Polars.all.str.len_bytes)
422
+ # # =>
423
+ # # shape: (2, 3)
424
+ # # ┌──────┬─────┬──────┐
425
+ # # │ text ┆ nfc ┆ nfkc │
426
+ # # │ --- ┆ --- ┆ --- │
427
+ # # │ u32 ┆ u32 ┆ u32 │
428
+ # # ╞══════╪═════╪══════╡
429
+ # # │ 4 ┆ 4 ┆ 3 │
430
+ # # │ 24 ┆ 24 ┆ 8 │
431
+ # # └──────┴─────┴──────┘
432
+ def normalize(form = "NFC")
433
+ Utils.wrap_expr(_rbexpr.str_normalize(form))
434
+ end
435
+
371
436
  # Transform to uppercase variant.
372
437
  #
373
438
  # @return [Expr]
@@ -707,6 +772,68 @@ module Polars
707
772
  Utils.wrap_expr(_rbexpr.str_contains(pattern, literal, strict))
708
773
  end
709
774
 
775
+ # Return the bytes offset of the first substring matching a pattern.
776
+ #
777
+ # If the pattern is not found, returns None.
778
+ #
779
+ # @param pattern [String]
780
+ # A valid regular expression pattern, compatible with the [regex crate](https://docs.rs/regex/latest/regex/).
781
+ # @param literal [Boolean]
782
+ # Treat `pattern` as a literal string, not as a regular expression.
783
+ # @param strict [Boolean]
784
+ # Raise an error if the underlying pattern is not a valid regex,
785
+ # otherwise mask out with a null value.
786
+ #
787
+ # @return [Expr]
788
+ #
789
+ # @note
790
+ # To modify regular expression behaviour (such as case-sensitivity) with
791
+ # flags, use the inline `(?iLmsuxU)` syntax.
792
+ #
793
+ # @example Find the index of the first substring matching a regex or literal pattern:
794
+ # df = Polars::DataFrame.new(
795
+ # {
796
+ # "txt" => ["Crab", "Lobster", nil, "Crustacean"],
797
+ # "pat" => ["a[bc]", "b.t", "[aeiuo]", "(?i)A[BC]"]
798
+ # }
799
+ # )
800
+ # df.select(
801
+ # Polars.col("txt"),
802
+ # Polars.col("txt").str.find("a|e").alias("a|e (regex)"),
803
+ # Polars.col("txt").str.find("e", literal: true).alias("e (lit)"),
804
+ # )
805
+ # # =>
806
+ # # shape: (4, 3)
807
+ # # ┌────────────┬─────────────┬─────────┐
808
+ # # │ txt ┆ a|e (regex) ┆ e (lit) │
809
+ # # │ --- ┆ --- ┆ --- │
810
+ # # │ str ┆ u32 ┆ u32 │
811
+ # # ╞════════════╪═════════════╪═════════╡
812
+ # # │ Crab ┆ 2 ┆ null │
813
+ # # │ Lobster ┆ 5 ┆ 5 │
814
+ # # │ null ┆ null ┆ null │
815
+ # # │ Crustacean ┆ 5 ┆ 7 │
816
+ # # └────────────┴─────────────┴─────────┘
817
+ #
818
+ # @example Match against a pattern found in another column or (expression):
819
+ # df.with_columns(Polars.col("txt").str.find(Polars.col("pat")).alias("find_pat"))
820
+ # # =>
821
+ # # shape: (4, 3)
822
+ # # ┌────────────┬───────────┬──────────┐
823
+ # # │ txt ┆ pat ┆ find_pat │
824
+ # # │ --- ┆ --- ┆ --- │
825
+ # # │ str ┆ str ┆ u32 │
826
+ # # ╞════════════╪═══════════╪══════════╡
827
+ # # │ Crab ┆ a[bc] ┆ 2 │
828
+ # # │ Lobster ┆ b.t ┆ 2 │
829
+ # # │ null ┆ [aeiuo] ┆ null │
830
+ # # │ Crustacean ┆ (?i)A[BC] ┆ 5 │
831
+ # # └────────────┴───────────┴──────────┘
832
+ def find(pattern, literal: false, strict: true)
833
+ pattern = Utils.parse_into_expression(pattern, str_as_lit: true)
834
+ Utils.wrap_expr(_rbexpr.str_find(pattern, literal, strict))
835
+ end
836
+
710
837
  # Check if string values end with a substring.
711
838
  #
712
839
  # @param sub [String]
@@ -1307,6 +1434,130 @@ module Polars
1307
1434
  Utils.wrap_expr(_rbexpr.str_slice(offset, length))
1308
1435
  end
1309
1436
 
1437
+ # Return the first n characters of each string in a String Series.
1438
+ #
1439
+ # @param n [Integer]
1440
+ # Length of the slice (integer or expression). Negative indexing is supported;
1441
+ # see note (2) below.
1442
+ #
1443
+ # @return [Expr]
1444
+ #
1445
+ # @note
1446
+ # 1) The `n` input is defined in terms of the number of characters in the (UTF8)
1447
+ # string. A character is defined as a [Unicode scalar value](https://www.unicode.org/glossary/#unicode_scalar_value). A single
1448
+ # character is represented by a single byte when working with ASCII text, and a
1449
+ # maximum of 4 bytes otherwise.
1450
+ #
1451
+ # 2) When the `n` input is negative, `head` returns characters up to the `n`th
1452
+ # from the end of the string. For example, if `n = -3`, then all characters
1453
+ # except the last three are returned.
1454
+ #
1455
+ # 3) If the length of the string has fewer than `n` characters, the full string is
1456
+ # returned.
1457
+ #
1458
+ # @example Return up to the first 5 characters:
1459
+ # df = Polars::DataFrame.new({"s" => ["pear", nil, "papaya", "dragonfruit"]})
1460
+ # df.with_columns(Polars.col("s").str.head(5).alias("s_head_5"))
1461
+ # # =>
1462
+ # # shape: (4, 2)
1463
+ # # ┌─────────────┬──────────┐
1464
+ # # │ s ┆ s_head_5 │
1465
+ # # │ --- ┆ --- │
1466
+ # # │ str ┆ str │
1467
+ # # ╞═════════════╪══════════╡
1468
+ # # │ pear ┆ pear │
1469
+ # # │ null ┆ null │
1470
+ # # │ papaya ┆ papay │
1471
+ # # │ dragonfruit ┆ drago │
1472
+ # # └─────────────┴──────────┘
1473
+ #
1474
+ # @example Return characters determined by column `n`:
1475
+ # df = Polars::DataFrame.new(
1476
+ # {
1477
+ # "s" => ["pear", nil, "papaya", "dragonfruit"],
1478
+ # "n" => [3, 4, -2, -5]
1479
+ # }
1480
+ # )
1481
+ # df.with_columns(Polars.col("s").str.head("n").alias("s_head_n"))
1482
+ # # =>
1483
+ # # shape: (4, 3)
1484
+ # # ┌─────────────┬─────┬──────────┐
1485
+ # # │ s ┆ n ┆ s_head_n │
1486
+ # # │ --- ┆ --- ┆ --- │
1487
+ # # │ str ┆ i64 ┆ str │
1488
+ # # ╞═════════════╪═════╪══════════╡
1489
+ # # │ pear ┆ 3 ┆ pea │
1490
+ # # │ null ┆ 4 ┆ null │
1491
+ # # │ papaya ┆ -2 ┆ papa │
1492
+ # # │ dragonfruit ┆ -5 ┆ dragon │
1493
+ # # └─────────────┴─────┴──────────┘
1494
+ def head(n)
1495
+ n = Utils.parse_into_expression(n)
1496
+ Utils.wrap_expr(_rbexpr.str_head(n))
1497
+ end
1498
+
1499
+ # Return the last n characters of each string in a String Series.
1500
+ #
1501
+ # @param n [Integer]
1502
+ # Length of the slice (integer or expression). Negative indexing is supported;
1503
+ # see note (2) below.
1504
+ #
1505
+ # @return [Expr]
1506
+ #
1507
+ # @note
1508
+ # 1) The `n` input is defined in terms of the number of characters in the (UTF8)
1509
+ # string. A character is defined as a [Unicode scalar value](https://www.unicode.org/glossary/#unicode_scalar_value). A single
1510
+ # character is represented by a single byte when working with ASCII text, and a
1511
+ # maximum of 4 bytes otherwise.
1512
+ #
1513
+ # 2) When the `n` input is negative, `tail` returns characters starting from the
1514
+ # `n`th from the beginning of the string. For example, if `n = -3`, then all
1515
+ # characters except the first three are returned.
1516
+ #
1517
+ # 3) If the length of the string has fewer than `n` characters, the full string is
1518
+ # returned.
1519
+ #
1520
+ # @example Return up to the last 5 characters:
1521
+ # df = Polars::DataFrame.new({"s" => ["pear", nil, "papaya", "dragonfruit"]})
1522
+ # df.with_columns(Polars.col("s").str.tail(5).alias("s_tail_5"))
1523
+ # # =>
1524
+ # # shape: (4, 2)
1525
+ # # ┌─────────────┬──────────┐
1526
+ # # │ s ┆ s_tail_5 │
1527
+ # # │ --- ┆ --- │
1528
+ # # │ str ┆ str │
1529
+ # # ╞═════════════╪══════════╡
1530
+ # # │ pear ┆ pear │
1531
+ # # │ null ┆ null │
1532
+ # # │ papaya ┆ apaya │
1533
+ # # │ dragonfruit ┆ fruit │
1534
+ # # └─────────────┴──────────┘
1535
+ #
1536
+ # @example Return characters determined by column `n`:
1537
+ # df = Polars::DataFrame.new(
1538
+ # {
1539
+ # "s" => ["pear", nil, "papaya", "dragonfruit"],
1540
+ # "n" => [3, 4, -2, -5]
1541
+ # }
1542
+ # )
1543
+ # df.with_columns(Polars.col("s").str.tail("n").alias("s_tail_n"))
1544
+ # # =>
1545
+ # # shape: (4, 3)
1546
+ # # ┌─────────────┬─────┬──────────┐
1547
+ # # │ s ┆ n ┆ s_tail_n │
1548
+ # # │ --- ┆ --- ┆ --- │
1549
+ # # │ str ┆ i64 ┆ str │
1550
+ # # ╞═════════════╪═════╪══════════╡
1551
+ # # │ pear ┆ 3 ┆ ear │
1552
+ # # │ null ┆ 4 ┆ null │
1553
+ # # │ papaya ┆ -2 ┆ paya │
1554
+ # # │ dragonfruit ┆ -5 ┆ nfruit │
1555
+ # # └─────────────┴─────┴──────────┘
1556
+ def tail(n)
1557
+ n = Utils.parse_into_expression(n)
1558
+ Utils.wrap_expr(_rbexpr.str_tail(n))
1559
+ end
1560
+
1310
1561
  # Convert an Utf8 column into an Int64 column with base radix.
1311
1562
  #
1312
1563
  # @param base [Integer]
@@ -1432,9 +1683,9 @@ module Polars
1432
1683
 
1433
1684
  # Use the aho-corasick algorithm to replace many matches.
1434
1685
  #
1435
- # @param patterns [String]
1686
+ # @param patterns [Object]
1436
1687
  # String patterns to search and replace.
1437
- # @param replace_with [String]
1688
+ # @param replace_with [Object]
1438
1689
  # Strings to replace where a pattern was a match.
1439
1690
  # This can be broadcasted. So it supports many:one and many:many.
1440
1691
  # @param ascii_case_insensitive [Boolean]
@@ -1494,11 +1745,22 @@ module Polars
1494
1745
  # # │ Tell me what you want, what yo… ┆ Tell you what me want, what me… │
1495
1746
  # # │ Can you feel the love tonight ┆ Can me feel the love tonight │
1496
1747
  # # └─────────────────────────────────┴─────────────────────────────────┘
1497
- def replace_many(patterns, replace_with, ascii_case_insensitive: false)
1748
+ def replace_many(patterns, replace_with = Expr::NO_DEFAULT, ascii_case_insensitive: false)
1749
+ if replace_with == Expr::NO_DEFAULT
1750
+ if !patterns.is_a?(Hash)
1751
+ msg = "`replace_with` argument is required if `patterns` argument is not a Hash type"
1752
+ raise TypeError, msg
1753
+ end
1754
+ # Early return in case of an empty mapping.
1755
+ if patterns.empty?
1756
+ return Utils.wrap_expr(_rbexpr)
1757
+ end
1758
+ replace_with = patterns.values
1759
+ patterns = patterns.keys
1760
+ end
1761
+
1498
1762
  patterns = Utils.parse_into_expression(patterns, str_as_lit: false)
1499
- replace_with = Utils.parse_into_expression(
1500
- replace_with, str_as_lit: true
1501
- )
1763
+ replace_with = Utils.parse_into_expression(replace_with, str_as_lit: true)
1502
1764
  Utils.wrap_expr(
1503
1765
  _rbexpr.str_replace_many(
1504
1766
  patterns, replace_with, ascii_case_insensitive
@@ -1506,6 +1768,149 @@ module Polars
1506
1768
  )
1507
1769
  end
1508
1770
 
1771
+ # Use the Aho-Corasick algorithm to extract many matches.
1772
+ #
1773
+ # @param patterns [Object]
1774
+ # String patterns to search.
1775
+ # @param ascii_case_insensitive [Boolean]
1776
+ # Enable ASCII-aware case-insensitive matching.
1777
+ # When this option is enabled, searching will be performed without respect
1778
+ # to case for ASCII letters (a-z and A-Z) only.
1779
+ # @param overlapping [Boolean]
1780
+ # Whether matches may overlap.
1781
+ #
1782
+ # @return [Expr]
1783
+ #
1784
+ # @note
1785
+ # This method supports matching on string literals only, and does not support
1786
+ # regular expression matching.
1787
+ #
1788
+ # @example
1789
+ # df = Polars::DataFrame.new({"values" => ["discontent"]})
1790
+ # patterns = ["winter", "disco", "onte", "discontent"]
1791
+ # df.with_columns(
1792
+ # Polars.col("values")
1793
+ # .str.extract_many(patterns, overlapping: false)
1794
+ # .alias("matches"),
1795
+ # Polars.col("values")
1796
+ # .str.extract_many(patterns, overlapping: true)
1797
+ # .alias("matches_overlapping"),
1798
+ # )
1799
+ # # =>
1800
+ # # shape: (1, 3)
1801
+ # # ┌────────────┬───────────┬─────────────────────────────────┐
1802
+ # # │ values ┆ matches ┆ matches_overlapping │
1803
+ # # │ --- ┆ --- ┆ --- │
1804
+ # # │ str ┆ list[str] ┆ list[str] │
1805
+ # # ╞════════════╪═══════════╪═════════════════════════════════╡
1806
+ # # │ discontent ┆ ["disco"] ┆ ["disco", "onte", "discontent"… │
1807
+ # # └────────────┴───────────┴─────────────────────────────────┘
1808
+ #
1809
+ # @example
1810
+ # df = Polars::DataFrame.new(
1811
+ # {
1812
+ # "values" => ["discontent", "rhapsody"],
1813
+ # "patterns" => [
1814
+ # ["winter", "disco", "onte", "discontent"],
1815
+ # ["rhap", "ody", "coalesce"]
1816
+ # ]
1817
+ # }
1818
+ # )
1819
+ # df.select(Polars.col("values").str.extract_many("patterns"))
1820
+ # # =>
1821
+ # # shape: (2, 1)
1822
+ # # ┌─────────────────┐
1823
+ # # │ values │
1824
+ # # │ --- │
1825
+ # # │ list[str] │
1826
+ # # ╞═════════════════╡
1827
+ # # │ ["disco"] │
1828
+ # # │ ["rhap", "ody"] │
1829
+ # # └─────────────────┘
1830
+ def extract_many(
1831
+ patterns,
1832
+ ascii_case_insensitive: false,
1833
+ overlapping: false
1834
+ )
1835
+ patterns = Utils.parse_into_expression(patterns, str_as_lit: false)
1836
+ Utils.wrap_expr(
1837
+ _rbexpr.str_extract_many(patterns, ascii_case_insensitive, overlapping)
1838
+ )
1839
+ end
1840
+
1841
+ # Use the Aho-Corasick algorithm to find many matches.
1842
+ #
1843
+ # The function will return the bytes offset of the start of each match.
1844
+ # The return type will be `List<UInt32>`
1845
+ #
1846
+ # @param patterns [Object]
1847
+ # String patterns to search.
1848
+ # @param ascii_case_insensitive [Boolean]
1849
+ # Enable ASCII-aware case-insensitive matching.
1850
+ # When this option is enabled, searching will be performed without respect
1851
+ # to case for ASCII letters (a-z and A-Z) only.
1852
+ # @param overlapping [Boolean]
1853
+ # Whether matches may overlap.
1854
+ #
1855
+ # @return [Expr]
1856
+ #
1857
+ # @note
1858
+ # This method supports matching on string literals only, and does not support
1859
+ # regular expression matching.
1860
+ #
1861
+ # @example
1862
+ # df = Polars::DataFrame.new({"values" => ["discontent"]})
1863
+ # patterns = ["winter", "disco", "onte", "discontent"]
1864
+ # df.with_columns(
1865
+ # Polars.col("values")
1866
+ # .str.extract_many(patterns, overlapping: false)
1867
+ # .alias("matches"),
1868
+ # Polars.col("values")
1869
+ # .str.extract_many(patterns, overlapping: true)
1870
+ # .alias("matches_overlapping"),
1871
+ # )
1872
+ # # =>
1873
+ # # shape: (1, 3)
1874
+ # # ┌────────────┬───────────┬─────────────────────────────────┐
1875
+ # # │ values ┆ matches ┆ matches_overlapping │
1876
+ # # │ --- ┆ --- ┆ --- │
1877
+ # # │ str ┆ list[str] ┆ list[str] │
1878
+ # # ╞════════════╪═══════════╪═════════════════════════════════╡
1879
+ # # │ discontent ┆ ["disco"] ┆ ["disco", "onte", "discontent"… │
1880
+ # # └────────────┴───────────┴─────────────────────────────────┘
1881
+ #
1882
+ # @example
1883
+ # df = Polars::DataFrame.new(
1884
+ # {
1885
+ # "values" => ["discontent", "rhapsody"],
1886
+ # "patterns" => [
1887
+ # ["winter", "disco", "onte", "discontent"],
1888
+ # ["rhap", "ody", "coalesce"]
1889
+ # ]
1890
+ # }
1891
+ # )
1892
+ # df.select(Polars.col("values").str.find_many("patterns"))
1893
+ # # =>
1894
+ # # shape: (2, 1)
1895
+ # # ┌───────────┐
1896
+ # # │ values │
1897
+ # # │ --- │
1898
+ # # │ list[u32] │
1899
+ # # ╞═══════════╡
1900
+ # # │ [0] │
1901
+ # # │ [0, 5] │
1902
+ # # └───────────┘
1903
+ def find_many(
1904
+ patterns,
1905
+ ascii_case_insensitive: false,
1906
+ overlapping: false
1907
+ )
1908
+ patterns = Utils.parse_into_expression(patterns, str_as_lit: false)
1909
+ Utils.wrap_expr(
1910
+ _rbexpr.str_find_many(patterns, ascii_case_insensitive, overlapping)
1911
+ )
1912
+ end
1913
+
1509
1914
  private
1510
1915
 
1511
1916
  def _validate_format_argument(format)