o
    ¹­§iß5  ã                   @  sœ   d dl mZ d dlZd dlmZmZ d dlmZ d dl	m
Z
 e e¡ d dlmZ W d  ƒ n1 s4w   Y  erGd dlmZ d dlmZ ddd„ZdS )é    )ÚannotationsN)ÚTYPE_CHECKINGÚAny)Ú,parse_predicates_constraints_into_expression)ÚIterable)ÚIntoExprColumnÚ
predicatesú0IntoExprColumn | Iterable[IntoExprColumn] | boolÚconstraintsr   Úreturnúpl.Whenc                  O  s   t | i |¤Ž}t t |¡¡S )u-3  
    Start a `when-then-otherwise` expression.

    Always initiated by a `pl.when().then()`., and optionally followed by chaining one
    or more `.when().then()` statements.

    An optional `.otherwise()` can be appended at the end. If not declared, a default
    of `.otherwise(None)` is used.

    Similar to :func:`coalesce`, the value from the first condition that
    evaluates to True will be picked.

    If all conditions are False, the `otherwise` value is picked.

    Parameters
    ----------
    predicates
        Condition(s) that must be met in order to apply the subsequent statement.
        Accepts one or more boolean expressions, which are implicitly combined with
        `&`.
    constraints
        Apply conditions as `col_name = value` keyword arguments that are treated as
        equality matches, such as `x = 123`. As with the predicates parameter, multiple
        conditions are implicitly combined using `&`.

    Warnings
    --------
    Polars computes all expressions passed to `when-then-otherwise` in parallel and
    filters afterwards. This means each expression must be valid on its own, regardless
    of the conditions in the `when-then-otherwise` chain.

    Notes
    -----
    * String inputs e.g. `when("string")`, `then("string")` or `otherwise("string")`
      are parsed as column names. :func:`lit` can be used to create string values.
    * The expression output name is taken from the first `then` statement. It is
      not affected by `predicates`, nor by `constraints`.

    Examples
    --------
    Below we add a column with the value 1, where column "foo" > 2 and the value
    1 + column "bar" where it isn't.

    >>> df = pl.DataFrame({"foo": [1, 3, 4], "bar": [3, 4, 0]})
    >>> df.with_columns(
    ...     pl.when(pl.col.foo > 2).then(1).otherwise(1 + pl.col.bar).alias("val")
    ... )
    shape: (3, 3)
    â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”
    â”‚ foo â”† bar â”† val â”‚
    â”‚ --- â”† --- â”† --- â”‚
    â”‚ i64 â”† i64 â”† i64 â”‚
    â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•ªâ•â•â•â•â•â•¡
    â”‚ 1   â”† 3   â”† 4   â”‚
    â”‚ 3   â”† 4   â”† 1   â”‚
    â”‚ 4   â”† 0   â”† 1   â”‚
    â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”˜

    Note that `when-then` always executes all expressions.

    The results are folded left to right, picking the `then` value from the first `when`
    condition that is True.

    If no `when` condition is True the `otherwise` value is picked.

    >>> df.with_columns(
    ...     when = pl.col.foo > 2,
    ...     then = 1,
    ...     otherwise = 1 + pl.col.bar
    ... ).with_columns(
    ...     pl.when("when").then("then").otherwise("otherwise").alias("val")
    ... )
    shape: (3, 6)
    â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”
    â”‚ foo â”† bar â”† when  â”† then â”† otherwise â”† val â”‚
    â”‚ --- â”† --- â”† ---   â”† ---  â”† ---       â”† --- â”‚
    â”‚ i64 â”† i64 â”† bool  â”† i32  â”† i64       â”† i64 â”‚
    â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•¡
    â”‚ 1   â”† 3   â”† false â”† 1    â”† 4         â”† 4   â”‚
    â”‚ 3   â”† 4   â”† true  â”† 1    â”† 5         â”† 1   â”‚
    â”‚ 4   â”† 0   â”† true  â”† 1    â”† 1         â”† 1   â”‚
    â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”˜

    Note that in regular Polars usage, a single string is parsed as a column name.

    >>> df.with_columns(
    ...     when = pl.col.foo > 2,
    ...     then = "foo",
    ...     otherwise = "bar"
    ... )
    shape: (3, 5)
    â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
    â”‚ foo â”† bar â”† when  â”† then â”† otherwise â”‚
    â”‚ --- â”† --- â”† ---   â”† ---  â”† ---       â”‚
    â”‚ i64 â”† i64 â”† bool  â”† i64  â”† i64       â”‚
    â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•¡
    â”‚ 1   â”† 3   â”† false â”† 1    â”† 3         â”‚
    â”‚ 3   â”† 4   â”† true  â”† 3    â”† 4         â”‚
    â”‚ 4   â”† 0   â”† true  â”† 4    â”† 0         â”‚
    â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜

    For consistency, `when-then` behaves in the same way.

    >>> df.with_columns(
    ...     pl.when(pl.col.foo > 2).then("foo").otherwise("bar").alias("val")
    ... )
    shape: (3, 3)
    â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”
    â”‚ foo â”† bar â”† val â”‚
    â”‚ --- â”† --- â”† --- â”‚
    â”‚ i64 â”† i64 â”† i64 â”‚
    â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•ªâ•â•â•â•â•â•¡
    â”‚ 1   â”† 3   â”† 3   â”‚
    â”‚ 3   â”† 4   â”† 3   â”‚
    â”‚ 4   â”† 0   â”† 4   â”‚
    â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”˜

    :func:`lit` can be used to create string values.

    >>> df.with_columns(
    ...     pl.when(pl.col.foo > 2)
    ...     .then(pl.lit("foo"))
    ...     .otherwise(pl.lit("bar"))
    ...     .alias("val")
    ... )
    shape: (3, 3)
    â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”
    â”‚ foo â”† bar â”† val â”‚
    â”‚ --- â”† --- â”† --- â”‚
    â”‚ i64 â”† i64 â”† str â”‚
    â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•ªâ•â•â•â•â•â•¡
    â”‚ 1   â”† 3   â”† bar â”‚
    â”‚ 3   â”† 4   â”† foo â”‚
    â”‚ 4   â”† 0   â”† foo â”‚
    â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”˜

    Multiple `when-then` statements can be chained.

    >>> df.with_columns(
    ...     pl.when(pl.col.foo > 2)
    ...     .then(1)
    ...     .when(pl.col.bar > 2)
    ...     .then(4)
    ...     .otherwise(-1)
    ...     .alias("val")
    ... )
    shape: (3, 3)
    â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”
    â”‚ foo â”† bar â”† val â”‚
    â”‚ --- â”† --- â”† --- â”‚
    â”‚ i64 â”† i64 â”† i32 â”‚
    â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•ªâ•â•â•â•â•â•¡
    â”‚ 1   â”† 3   â”† 4   â”‚
    â”‚ 3   â”† 4   â”† 1   â”‚
    â”‚ 4   â”† 0   â”† 1   â”‚
    â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”˜

    In the case of `foo=3` and `bar=4`, both conditions are True but the first value
    (i.e. 1) is picked.

    >>> df.with_columns(
    ...     when1 = pl.col.foo > 2,
    ...     then1 = 1,
    ...     when2 = pl.col.bar > 2,
    ...     then2 = 4,
    ...     otherwise = -1
    ... )
    shape: (3, 7)
    â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
    â”‚ foo â”† bar â”† when1 â”† then1 â”† when2 â”† then2 â”† otherwise â”‚
    â”‚ --- â”† --- â”† ---   â”† ---   â”† ---   â”† ---   â”† ---       â”‚
    â”‚ i64 â”† i64 â”† bool  â”† i32   â”† bool  â”† i32   â”† i32       â”‚
    â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•¡
    â”‚ 1   â”† 3   â”† false â”† 1     â”† true  â”† 4     â”† -1        â”‚
    â”‚ 3   â”† 4   â”† true  â”† 1     â”† true  â”† 4     â”† -1        â”‚
    â”‚ 4   â”† 0   â”† true  â”† 1     â”† false â”† 4     â”† -1        â”‚
    â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜

    The `otherwise` statement is optional and defaults to `.otherwise(None)`
    if not given.

    This idiom is commonly used to null out values.

    >>> df.with_columns(pl.when(pl.col.foo == 3).then("bar"))
    shape: (3, 2)
    â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”
    â”‚ foo â”† bar  â”‚
    â”‚ --- â”† ---  â”‚
    â”‚ i64 â”† i64  â”‚
    â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•â•¡
    â”‚ 1   â”† null â”‚
    â”‚ 3   â”† 4    â”‚
    â”‚ 4   â”† null â”‚
    â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”˜

    `when` accepts keyword arguments as shorthand for equality conditions.

    >>> df.with_columns(pl.when(foo=3).then("bar"))
    shape: (3, 2)
    â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”
    â”‚ foo â”† bar  â”‚
    â”‚ --- â”† ---  â”‚
    â”‚ i64 â”† i64  â”‚
    â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•â•¡
    â”‚ 1   â”† null â”‚
    â”‚ 3   â”† 4    â”‚
    â”‚ 4   â”† null â”‚
    â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”˜

    Multiple predicates passed to `when` are combined with `&`

    >>> df.with_columns(
    ...     pl.when(pl.col.foo > 2, pl.col.bar < 3) # when((pred1) & (pred2))
    ...     .then(pl.lit("Yes"))
    ...     .otherwise(pl.lit("No"))
    ...     .alias("val")
    ... )
    shape: (3, 3)
    â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”
    â”‚ foo â”† bar â”† val â”‚
    â”‚ --- â”† --- â”† --- â”‚
    â”‚ i64 â”† i64 â”† str â”‚
    â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•ªâ•â•â•â•â•â•¡
    â”‚ 1   â”† 3   â”† No  â”‚
    â”‚ 3   â”† 4   â”† No  â”‚
    â”‚ 4   â”† 0   â”† Yes â”‚
    â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”˜

    It could also be thought of as an implicit :func:`all_horizontal` being present.

    >>> df.with_columns(
    ...     when = pl.all_horizontal(pl.col.foo > 2, pl.col.bar < 3)
    ... )
    shape: (3, 3)
    â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”
    â”‚ foo â”† bar â”† when  â”‚
    â”‚ --- â”† --- â”† ---   â”‚
    â”‚ i64 â”† i64 â”† bool  â”‚
    â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•¡
    â”‚ 1   â”† 3   â”† false â”‚
    â”‚ 3   â”† 4   â”† false â”‚
    â”‚ 4   â”† 0   â”† true  â”‚
    â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”˜

    Structs can be used as a way to return multiple values.

    Here we swap the "foo" and "bar" values when "foo" is greater than 2.

    >>> df.with_columns(
    ...     pl.when(pl.col.foo > 2)
    ...     .then(pl.struct(foo="bar", bar="foo"))
    ...     .otherwise(pl.struct("foo", "bar"))
    ...     .struct.unnest()
    ... )
    shape: (3, 2)
    â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”
    â”‚ foo â”† bar â”‚
    â”‚ --- â”† --- â”‚
    â”‚ i64 â”† i64 â”‚
    â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•¡
    â”‚ 1   â”† 3   â”‚
    â”‚ 4   â”† 3   â”‚
    â”‚ 0   â”† 4   â”‚
    â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”˜

    The struct fields are given the same name as the target columns, which are then
    unnested.

    >>> df.with_columns(
    ...     when = pl.col.foo > 2,
    ...     then = pl.struct(foo="bar", bar="foo"),
    ...     otherwise = pl.struct("foo", "bar")
    ... )
    shape: (3, 5)
    â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”
    â”‚ foo â”† bar â”† when  â”† then      â”† otherwise â”‚
    â”‚ --- â”† --- â”† ---   â”† ---       â”† ---       â”‚
    â”‚ i64 â”† i64 â”† bool  â”† struct[2] â”† struct[2] â”‚
    â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•ªâ•â•â•â•â•â•â•â•â•â•â•â•¡
    â”‚ 1   â”† 3   â”† false â”† {3,1}     â”† {1,3}     â”‚
    â”‚ 3   â”† 4   â”† true  â”† {4,3}     â”† {3,4}     â”‚
    â”‚ 4   â”† 0   â”† true  â”† {0,4}     â”† {4,0}     â”‚
    â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜

    The output name of a `when-then` expression comes from the first `then` branch.

    Here we try to set all columns to 0 if any column contains a value less than 2.

    >>> df.with_columns( # doctest: +SKIP
    ...    pl.when(pl.any_horizontal(pl.all() < 2))
    ...    .then(0)
    ...    .otherwise(pl.all())
    ... )
    # ComputeError: the name 'literal' passed to `LazyFrame.with_columns` is duplicate

    :meth:`.name.keep` could be used to give preference to the column expression.

    >>> df.with_columns(
    ...    pl.when(pl.any_horizontal(pl.all() < 2))
    ...    .then(0)
    ...    .otherwise(pl.all())
    ...    .name.keep()
    ... )
    shape: (3, 2)
    â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”
    â”‚ foo â”† bar â”‚
    â”‚ --- â”† --- â”‚
    â”‚ i64 â”† i64 â”‚
    â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•¡
    â”‚ 0   â”† 0   â”‚
    â”‚ 3   â”† 4   â”‚
    â”‚ 0   â”† 0   â”‚
    â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”˜

    The logic could also be changed to move the column expression inside `then`.

    >>> df.with_columns(
    ...     pl.when(pl.any_horizontal(pl.all() < 2).not_())
    ...     .then(pl.all())
    ...     .otherwise(0)
    ... )
    shape: (3, 2)
    â”Œâ”€â”€â”€â”€â”€â”¬â”€â”€â”€â”€â”€â”
    â”‚ foo â”† bar â”‚
    â”‚ --- â”† --- â”‚
    â”‚ i64 â”† i64 â”‚
    â•žâ•â•â•â•â•â•ªâ•â•â•â•â•â•¡
    â”‚ 0   â”† 0   â”‚
    â”‚ 3   â”† 4   â”‚
    â”‚ 0   â”† 0   â”‚
    â””â”€â”€â”€â”€â”€â”´â”€â”€â”€â”€â”€â”˜
    )r   ÚplZWhenÚplrÚwhen)r   r
   Ú	condition© r   úP/home/app/Keep/.python/lib/python3.10/site-packages/polars/functions/whenthen.pyr      s     Rr   )r   r	   r
   r   r   r   )Ú
__future__r   Ú
contextlibÚtypingr   r   Zpolars._reexportZ	_reexportr   Zpolars._utils.parser   ÚsuppressÚImportErrorZpolars._plrZ_plrr   Úcollections.abcr   Zpolars._typingr   r   r   r   r   r   Ú<module>   s    ÿ