推荐学习书目
› Learn Python the Hard Way
Python Sites
› PyPI - Python Package Index
› http://diveintopython.org/toc/index.html
› Pocoo
值得关注的项目
› PyPy
› Celery
› Jinja2
› Read the Docs
› gevent
› pyenv
› virtualenv
› Stackless Python
› Beautiful Soup
› 结巴中文分词
› Green Unicorn
› Sentry
› Shovel
› Pyflakes
› pytest
Python 编程
› pep8 Checker
Styles
› PEP 8
› Google Python Style Guide
› Code Style from The Hitchhiker's Guide
Dragonish3600
V2EX  ›  Python

如何用 map 和 re 来优化下面的 if..else..

  •  1
     
  •   Dragonish3600 · Jun 23, 2023 · 5484 views
    This topic created in 1228 days ago, the information mentioned may be changed or developed.

    代码如下

    long_string ="blablabl"
    
    my_dict = {"a": "string1", "b": "string2" , "c": "string3", "d":"string4"}
    
    if "Andy" in long_string:
        return mydict["a"]
    elif "Jack" in long_string:
        return mydict["b"]
    elif "Jim" in long_string and "Mike" not in long_string:
        return mydict["c"]
    else:
        return mydict["d"]
    

    感觉这样效率有点低,感觉用 map 处理比较好。但是条件 3 实际上是 2 个条件,这样用 map 反而不好写了。

    请问大家有啥好的建议?

    谢谢

    47 replies  •  2023-07-14 17:43:13 +08:00
    BeautifulSoap
    BeautifulSoap
    Jun 23, 2023 via Android
    1
    写个循环遍历 long_string ,一次循环就能判定了
    Dragonish3600
    Dragonish3600
    OP
    Jun 23, 2023
    2
    @BeautifulSoap 一次?求范例,谢谢
    westoy
    westoy
    Jun 23, 2023
    3
    就就几个条件, 这样写挺好的
    ccde8259
    ccde8259
    Jun 23, 2023 via iPhone
    4
    为什么是 map 和 re 而不是 DFA 啊……
    luozic
    luozic
    Jun 23, 2023
    5
    原始需求是啥? 你这算字符串转义?
    Dragonish3600
    Dragonish3600
    OP
    Jun 23, 2023
    6
    @luozic 需求就是查询字符串 long_string 里有没有指定的字符串,然后返回字典的数值。
    要求用 map 和 re 解决
    LoNeFong
    LoNeFong
    Jun 23, 2023
    7
    long_string = "blablabl"

    my_dict = {"a": "string1", "b": "string2", "c": "string3", "d": "string4"}

    result = my_dict["a"] if "Andy" in long_string else my_dict["b"] if "Jack" in long_string else my_dict["c"] if "Jim" in long_string and "Mike" not in long_string else my_dict["d"]

    result
    keenkiller
    keenkiller
    Jun 23, 2023 via Android
    8
    让 gpt 优化就行 专业对口
    BeautifulSoap
    BeautifulSoap
    Jun 23, 2023
    9
    @luozic 看了 lz 的回复有一点不太明白了,你想改善的到底是那一坨 if 的判断逻辑,还是想改善那一坨 if 里的多个 in 查找?
    JasonLaw
    JasonLaw
    Jun 23, 2023
    10
    @LoNeFong #7 这代码没有一点可读性🤕
    Dragonish3600
    Dragonish3600
    OP
    Jun 23, 2023 via iPhone
    11
    @BeautifulSoap 就是不要用 if 而是用 map 来实现
    blankmiss
    blankmiss
    Jun 23, 2023
    12
    gpt 给的答案 def get_value(long_string):
    string_map = {
    "Andy": "string1",
    "Jack": "string2",
    "Jim": "string3",
    "Mike": "not_found",
    }

    return next(map(lambda key: string_map[key], filter(lambda key: key in long_string and (key != "Jim" or "Mike" not in long_string), string_map)), "string4")

    可是这样真的好吗
    Jakarta
    Jakarta
    Jun 23, 2023 via Android
    13
    @blankmiss 优雅,俺们 v2 就是追求这样的代码
    lhbc
    lhbc
    Jun 23, 2023 via Android
    14
    先遍历找出所有的关键词是否存在,存到一个字典里,然后判断返回

    但没必要这样优化
    你的逻辑是满足其中一个条件就 return 了,其他都没必要找
    先找出所有的反而效率低

    除非你的字符串极长
    Dragonish3600
    Dragonish3600
    OP
    Jun 23, 2023 via iPhone
    15
    @tairan2006 试了下,需要多次才能给出差不多的答案,但是个人感觉这种可读性还不如 if else

    import re

    long_string = "blablabl"

    my_dict = {"a": "string1", "b": "string2", "c": "string3", "d": "string4"}

    keyword_mapping = {
    "Andy": "a",
    "Jack": "b",
    "Jim": "c",
    "Mike": "d"
    }

    matched_keywords = set(filter(lambda x: re.search(x, long_string) is not None, keyword_mapping.keys()))
    matched_values = [my_dict[keyword_mapping[keyword]] for keyword in matched_keywords]

    if "Jim" in matched_keywords and "Mike" not in matched_keywords:
    result = my_dict[keyword_mapping["Jim"]]
    else:
    result = matched_values[0] if matched_values else my_dict["d"]

    print(result)
    Pastsong
    Pastsong
    Jun 23, 2023 via Android
    16
    不可读吗?比正则可读吧
    liantian
    liantian
    Jun 23, 2023 via iPhone
    17
    看了楼上各种解决方案…

    还是原始方案最可读啊。
    shxxy
    shxxy
    Jun 23, 2023
    18
    luozic
    luozic
    Jun 23, 2023
    19
    @BeautifulSoap 看这 lz 还是有点故意把能优化成 DFA 的,用 re+map 处理? 关键这种字典映射,只取一个就返回?
    luozic
    luozic
    Jun 23, 2023
    20
    https://paste.ubuntu.com/p/pFwm9WPymf/
    @qwq11 拼写单词错误,语法错误
    BeautifulSoap
    BeautifulSoap
    Jun 23, 2023
    21
    @luozic cc: @luozic

    1. 单纯的可读性,我觉得 lz 这一坨 if 已经是可读性很好了,没必要纠结,因为这段代码最大的问题不在这一坨 if 的可读性上。如果 if 的判断条件非常多,而且确保 if 中只有 and 的逻辑关系,应该用数组而不是字典。可以参考这里第一个代码片段。本质上就是把 if 给写成数组
    https://gist.github.com/WonderfulSoap/333ccfd1b017728b928354bacdd1fa47

    2. lz 代码主要问题出在每一个 if 判断就要从头查找一遍 long_string 。Andy 没找到,下一个 if 文里就又从头找一遍 Jack ,一次类推。如果要找的关键词很多最坏的情况要遍历 long_string N 次。所以 lz 代码最大问题是应该怎么优化这个问题争取只遍历一遍 long_string 就行。解决办法就是写一个工具类,如 FindWord("Andy"),然后一个个字符往里面塞,然后找到了的话返回找到
    这代码参考第二个代码片段
    https://gist.github.com/WonderfulSoap/333ccfd1b017728b928354bacdd1fa47
    luozic
    luozic
    Jun 23, 2023
    22
    明明更合适的是更少的遍历, 一次就把要映射的 dict 全取出来。
    @BeautifulSoap kmp or dfa 整上啊。。。
    BeautifulSoap
    BeautifulSoap
    Jun 23, 2023
    23
    @BeautifulSoap 优化了一下第二个代码,防止 Andy 存在时依旧遍历了整个数组
    BeautifulSoap
    BeautifulSoap
    Jun 23, 2023
    24
    @luozic 不好意思,俺整不来 DFA orz
    Ericcccccccc
    Ericcccccccc
    Jun 23, 2023
    25
    很显然, 原始的代码是最好的, 下面的"优化"都是啥..
    jeesk
    jeesk
    Jun 23, 2023
    26
    分支多就用 when, 一半情况下直接 if else, 除非是代码量极大或者需要定制化才用策略模式, 切勿过渡优化
    shxxy
    shxxy
    Jun 23, 2023
    27
    @luozic #20 单词错误没找到,可能是打快了,语法不是 py 的语法,伪代码而已,思路到位就行
    fairyex
    fairyex
    Jun 23, 2023 via Android
    28
    这类问题最适合问 GPT4 了
    wxf666
    wxf666
    Jun 23, 2023 via Android
    29
    用 Python 实现的逐字符遍历,可能还真的比不上几次 in 呢。。

    可能用正则来干可以。/Andy|Jack|Jim|Mike/,然后匹配到后回调判断
    luozic
    luozic
    Jun 23, 2023
    30
    隐写反写回来? pypi 上 dfa kmp 有啊 https://pypi.org/project/kmp-utils/
    fregie
    fregie
    Jun 23, 2023
    31
    如果是想优化性能(虽然我觉得你的目的可能不是),用"Andy","Jack"这些构建一个 radix tree ,再来匹配 long_string 。
    Dragonish3600
    Dragonish3600
    OP
    Jun 23, 2023
    32
    还是试着用 re 改写了下

    long_string = "blablabl"

    my_dict = {"a": "string1", "b": "string2" , "c": "string3", "d":"string4"}

    patterns = {
    r"(?=.*Andy)": "a";
    r"(?=.*Jack)": "b",
    r"(?=.*Jim)(?!.*Mike)": "c",
    }

    matches = [patterns[pattern_key] for pattern_key in patterns.keys() if re.search(pattern_key, long_string)]

    if matches:
    return my_dict[matches[0]]
    else:
    return my_dict["d"]

    但是个人感觉还是不如 if ..else 直观
    txhwind
    txhwind
    Jun 23, 2023
    33
    就这种短路分支逻辑,long string 能有多 long 啊,根本不到考虑效率的时刻吧。。
    zhenghuiy
    zhenghuiy
    Jun 23, 2023
    34
    我个人的观点是,不要拿着锤子去找钉子。。而是发现钉子后找个合适的锤子。if else 没有啥不好的,该用 if else 而故意不用反而搞复杂了。
    noahliaszn
    noahliaszn
    Jun 24, 2023❤️1
    35
    舍本逐末
    yucongo
    yucongo
    Jun 24, 2023
    36
    name2abc = dict(zip(names, my_dict))

    _ = name2abc.get(name)
    return my_dict.get(_, "string4")


    如何
    t133
    t133
    Jun 24, 2023 via iPhone
    37
    这几个语句执行时间不超过 100ns 如果真的调用很多次应该考虑向量化
    yucongo
    yucongo
    Jun 24, 2023
    38
    ···python
    names = ["Andy", "Jack", "Jim"]
    name2abc = dict(zip(names, my_dict))

    for name in names:
    if name in long_string:
    _ = name2abc.get(name)
    print(my_dict.get(_))
    break
    else:
    print("string4")
    ```
    这个吧,用 return 代替 print 的话,break 和 else 都可以去掉
    zhouxiaoyuan
    zhouxiaoyuan
    Jun 24, 2023 via Android
    39
    @ladypxy 试着帮你简化下,正则表达式可能不正确,自己修复下:
    long_string = "blablabl"

    my_dict = {
    r"(?=.*Andy)": "string1";
    r"(?=.*Jack)": "string2",
    r"(?=.*Jim)(?!.*Mike)": "string3",
    r".*":"string4",
    }

    return [my_dict[pattern_key] for pattern_key in my_dict.keys() if re.search(pattern_key, long_string)][0]
    zhouxiaoyuan
    zhouxiaoyuan
    Jun 24, 2023 via Android
    40
    @zhouxiaoyuan 当然,for 循环提前 return 退出性能更优,当选项变多时
    zhouxiaoyuan
    zhouxiaoyuan
    Jun 24, 2023 via Android
    41
    @zhouxiaoyuan 对了,应该用 OrderedDict([('foo', 1), ('bar', 2), ('spam', 3), ('grok', 4)])
    cornetCat
    cornetCat
    Jun 24, 2023
    42
    就 if else 挺好的,可读性好,打断点调试方便
    yucongo
    yucongo
    Jun 24, 2023
    43
    names = ["Andy", "Jack", "Jim"]
    _ = [*map(lambda x: x in long_string, names)]
    idx = _.index(True) if True in _ else len(_)
    print(my_dict[list(my_dict)[idx]])

    坚持用 map 的话试试这个
    fgwmlhdkkkw
    fgwmlhdkkkw
    Jun 24, 2023 via Android
    44
    match
    fgwmlhdkkkw
    fgwmlhdkkkw
    Jun 24, 2023 via Android
    45
    yucongo
    yucongo
    Jun 24, 2023
    46
    def f(long_string):
    names = ["Andy", "Jack", "Jim"]
    _ = [*map(lambda x: x in long_string and (True if x not in ['Jim'] else 'Mike' not in long_string), names)]
    idx = _.index(True) if True in _ else len(_)
    return my_dict[list(my_dict)[idx]]

    assert f('Andy...') == 'string1'
    assert f('AndyJack...') == 'string1'
    assert f('JackAndy...') == 'string1'
    assert f('JackAndyJim...') == 'string1'
    assert f('AndyJimMike...') == 'string1'

    assert f('Jim...') == 'string3'
    assert f('JimMike...') == 'string4'

    assert f('xyz...') == 'string4'


    ‘Jim’ 加上 'Mike' not in long_string 条件
    xzm429438709
    xzm429438709
    Jul 14, 2023 via Android
    47
    真的如果单纯为了炫技,那可以,如果生产用,前往不要,if else 可读性最高,应届生来了都能接手,你搞的花里胡哨,性能提升了多少?如果不是,为什么搞?单纯为了装逼吗?减少代码行数?你底层最终的字节码,还不是 if else
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   4369 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 70ms · UTC 03:56 · PVG 11:56 · LAX 19:56 · JFK 22:56
    ♥ Do have faith in what you're doing.