代码如下
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 反而不好写了。
请问大家有啥好的建议?
谢谢
1
BeautifulSoap 2023-06-23 14:58:05 +08:00 via Android
写个循环遍历 long_string ,一次循环就能判定了
|
2
ladypxy OP @BeautifulSoap 一次?求范例,谢谢
|
3
westoy 2023-06-23 15:10:10 +08:00
就就几个条件, 这样写挺好的
|
4
ccde8259 2023-06-23 15:16:16 +08:00 via iPhone
为什么是 map 和 re 而不是 DFA 啊……
|
5
luozic 2023-06-23 15:36:15 +08:00
原始需求是啥? 你这算字符串转义?
|
6
ladypxy OP @luozic 需求就是查询字符串 long_string 里有没有指定的字符串,然后返回字典的数值。
要求用 map 和 re 解决 |
7
LoNeFong 2023-06-23 15:59:25 +08:00
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 |
8
tairan2006 2023-06-23 16:07:56 +08:00 via Android
让 gpt 优化就行 专业对口
|
9
BeautifulSoap 2023-06-23 16:16:18 +08:00
@luozic 看了 lz 的回复有一点不太明白了,你想改善的到底是那一坨 if 的判断逻辑,还是想改善那一坨 if 里的多个 in 查找?
|
11
ladypxy OP @BeautifulSoap 就是不要用 if 而是用 map 来实现
|
12
blankmiss 2023-06-23 16:41:12 +08:00
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") 可是这样真的好吗 |
14
lhbc 2023-06-23 16:56:34 +08:00 via Android
先遍历找出所有的关键词是否存在,存到一个字典里,然后判断返回
但没必要这样优化 你的逻辑是满足其中一个条件就 return 了,其他都没必要找 先找出所有的反而效率低 除非你的字符串极长 |
15
ladypxy OP @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) |
16
Pastsong 2023-06-23 17:08:06 +08:00 via Android
不可读吗?比正则可读吧
|
17
liantian 2023-06-23 17:23:41 +08:00 via iPhone
看了楼上各种解决方案…
还是原始方案最可读啊。 |
18
qwq11 2023-06-23 17:35:24 +08:00
|
19
luozic 2023-06-23 17:36:52 +08:00
@BeautifulSoap 看这 lz 还是有点故意把能优化成 DFA 的,用 re+map 处理? 关键这种字典映射,只取一个就返回?
|
20
luozic 2023-06-23 17:43:44 +08:00
|
21
BeautifulSoap 2023-06-23 17:52:56 +08:00
@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 |
22
luozic 2023-06-23 18:02:07 +08:00
明明更合适的是更少的遍历, 一次就把要映射的 dict 全取出来。
@BeautifulSoap kmp or dfa 整上啊。。。 |
23
BeautifulSoap 2023-06-23 18:05:39 +08:00
@BeautifulSoap 优化了一下第二个代码,防止 Andy 存在时依旧遍历了整个数组
|
24
BeautifulSoap 2023-06-23 18:06:41 +08:00
@luozic 不好意思,俺整不来 DFA orz
|
25
Ericcccccccc 2023-06-23 18:07:19 +08:00
很显然, 原始的代码是最好的, 下面的"优化"都是啥..
|
26
jeesk 2023-06-23 18:10:13 +08:00
分支多就用 when, 一半情况下直接 if else, 除非是代码量极大或者需要定制化才用策略模式, 切勿过渡优化
|
28
fairyex 2023-06-23 18:24:17 +08:00 via Android
这类问题最适合问 GPT4 了
|
29
wxf666 2023-06-23 18:36:01 +08:00 via Android
用 Python 实现的逐字符遍历,可能还真的比不上几次 in 呢。。
可能用正则来干可以。/Andy|Jack|Jim|Mike/,然后匹配到后回调判断 |
30
luozic 2023-06-23 18:39:49 +08:00
隐写反写回来? pypi 上 dfa kmp 有啊 https://pypi.org/project/kmp-utils/
|
31
fregie 2023-06-23 18:48:45 +08:00
如果是想优化性能(虽然我觉得你的目的可能不是),用"Andy","Jack"这些构建一个 radix tree ,再来匹配 long_string 。
|
32
ladypxy OP 还是试着用 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 直观 |
33
txhwind 2023-06-23 22:09:29 +08:00
就这种短路分支逻辑,long string 能有多 long 啊,根本不到考虑效率的时刻吧。。
|
34
zhenghuiy 2023-06-23 23:10:17 +08:00
我个人的观点是,不要拿着锤子去找钉子。。而是发现钉子后找个合适的锤子。if else 没有啥不好的,该用 if else 而故意不用反而搞复杂了。
|
35
Alias4ck 2023-06-24 00:02:25 +08:00 1
舍本逐末
|
36
yucongo 2023-06-24 09:32:27 +08:00
name2abc = dict(zip(names, my_dict))
_ = name2abc.get(name) return my_dict.get(_, "string4") 如何 |
37
t133 2023-06-24 09:33:19 +08:00 via iPhone
这几个语句执行时间不超过 100ns 如果真的调用很多次应该考虑向量化
|
38
yucongo 2023-06-24 09:59:49 +08:00
···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 都可以去掉 |
39
zhouxiaoyuan 2023-06-24 10:37:55 +08:00 via Android
@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] |
40
zhouxiaoyuan 2023-06-24 10:40:00 +08:00 via Android
@zhouxiaoyuan 当然,for 循环提前 return 退出性能更优,当选项变多时
|
41
zhouxiaoyuan 2023-06-24 11:00:37 +08:00 via Android
@zhouxiaoyuan 对了,应该用 OrderedDict([('foo', 1), ('bar', 2), ('spam', 3), ('grok', 4)])
|
42
cornetCat 2023-06-24 11:27:37 +08:00
就 if else 挺好的,可读性好,打断点调试方便
|
43
yucongo 2023-06-24 11:34:51 +08:00
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 的话试试这个 |
44
fgwmlhdkkkw 2023-06-24 13:09:10 +08:00 via Android
match
|
45
fgwmlhdkkkw 2023-06-24 13:09:54 +08:00 via Android
|
46
yucongo 2023-06-24 14:56:19 +08:00
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 条件 |
47
xzm429438709 2023-07-14 17:43:13 +08:00 via Android
真的如果单纯为了炫技,那可以,如果生产用,前往不要,if else 可读性最高,应届生来了都能接手,你搞的花里胡哨,性能提升了多少?如果不是,为什么搞?单纯为了装逼吗?减少代码行数?你底层最终的字节码,还不是 if else
|