代码之家  ›  专栏  ›  技术社区  ›  Semisonic

如何在列表理解中添加额外的中间步骤?

  •  5
  • Semisonic  · 技术社区  · 2 年前

    假设我有一个 typing.List[str] 对象中包含时间戳 "HH:mm" 格式,例如。

    timestamps = ["22:58", "03:11", "12:21"]
    

    我想把它转换成 typing.List[int] 对象,并为每个时间戳指定“自午夜起的分钟数”:

    converted = [22*60+58, 3*60+11, 12*60+21]
    

    ..., 但我想用一种风格,用一个列表来理解。 我天真地构造了一个(语法上不正确的)实现

    def timestamps_to_minutes(timestamps: typing.List[str]) -> typing.List[int]:
        return [int(hh) * 60 + int(mm) for ts in timestamps for hh, mm = ts.split(":")]
    

    ,但这不起作用,因为 for hh, mm = ts.split(":") 不是有效的语法。。。

    写同样的东西的有效方式是什么?

    澄清一下:我可以看到一个形式上令人满意的解决方案

    def timestamps_to_minutes(timestamps: typing.List[str]) -> typing.List[int]:
        return [int(ts.split(":")[0]) * 60 + int(ts.split(":")[1]) for ts in timestamps]
    

    ,但这是非常低效的,我不想将字符串拆分两次。

    4 回复  |  直到 2 年前
        1
  •  6
  •   wjandrea Geographos    2 年前

    可以使用内部生成器表达式进行拆分:

    [int(hh)*60 + int(mm) for hh, mm in (ts.split(':') for ts in timestamps)]
    

    虽然就我个人而言,我更愿意使用助手函数:

    def timestamp_to_minutes(timestamp: str) -> int:
        hh, mm = timestamp.split(":")
        return int(hh)*60 + int(mm)
    
    [timestamp_to_minutes(ts) for ts in timestamps]
    
    # Alternative
    list(map(timestamp_to_minutes, timestamps))
    
        2
  •  4
  •   Andrej Kesely    2 年前

    如果不想将字符串拆分两次,可以使用 := 分配操作员:

    timestamps = [int((s := t.split(":"))[0]) * 60 + int(s[1]) for t in timestamps]
    print(timestamps)
    

    印刷品:

    [1378, 191, 741]
    

    备选方案:

    print([int(h) * 60 + int(m) for h, m in (t.split(":") for t in timestamps)])
    

    印刷品:

    [1378, 191, 741]
    
        3
  •  2
  •   Patrick Artner    2 年前

    晚会迟到了。。但是为什么不使用datetime/timedelta来转换时间呢?

    对于“hh:mm”,这可能有些过分,但您可以轻松地将其调整为更复杂的时间字符串:

    from datetime import datetime as dt
    import typing
    
    def timestamps_to_minutes(timestamps: typing.List[str]) -> typing.List[any]:
        """Uses datetime.strptime to parse a datetime string and return
        minutes spent in this day."""
        return [int(((p:=dt.strptime(t,"%H:%M")) - dt(p.year,p.month, p.day)
                     ).total_seconds()//60) for t in timestamps]
    
    timestamps = ["22:58", "03:11", "12:21"]
    
    print(timestamps_to_minutes(timestamps))
    

    产出:

    [1378, 191, 741]
    
        4
  •  1
  •   enke    2 年前

    只是为了好玩,我们也可以 operator.methodcaller :

    from operator import methodcaller
    out = [int(h) * 60 + int(m) for h, m in map(methodcaller("split", ":"), timestamps)]
    

    输出:

    [1378, 191, 741]