Python 中 dict 的比较问题

2019-11-28 23:18:47 +08:00
 HHH01

写了一个作业,比较两个单词,看前一个单词能否用后一个单词中的字母拼接出来。 Your task will be to write a function can_be_composed(word1, word2) to check if word1 can be composed from word2 . Put your function into a file compose.py. Example usages: • can_be_composed("python", "pantyhose") returns True • can_be_composed("python", "ponytail") returns False • can_be_composed("code", "docent") returns True • can_be_composed("messy", "reassembly") returns True • can_be_composed("computational", "alphanumeric") returns False • can_be_composed("linguistics", "criminologists") returns False

思路是先把单词转换成 dict,然后再比较, import collections def word2dict(word):

word2dict=dict(collections.Counter(word))

return word2dict

def can_be_composed(word1,word2): dw1=word2dict(word1) dw2=word2dict(word2)

for key in dw1.keys():
    if key in list(dw2.keys()) and dw1[key] <= dw2[key]:
       return True
        
    else:
        return False

但是我每次得出的都是 True,后来发现, for key in dw1.keys(): if key in list(dw2.keys()) and dw1[key] <= dw2[key]: return True

这得出的结果是每个 key 的值的比较,输出的是一系列的对比结果,

问题来了,对于 if key in list(dw2.keys()) and dw1[key] <= dw2[key]:,如何能够在对比只要得出 false 就输出 false,只有全部都是 True 才输出 true ?

或者有没有更简单的方法?

附上原题, Exercise 3. We will say that a word “can be composed” from another word if it is possible to select some of the letters from the second word (maybe all of them) to build the first one (possibly changing the order). For example, word “python” can be composed from words “pantyhose”, “immunotherapy”, or “hypnotists”. It can not be composed from word “ponytail” because “ponytail” does not have a letter “h”. Similarly, word “lesson” can be composed from “professional” or “responsible”, but it can not be composed from word “longest” as “longest” does not have enough “s” letters. Your task will be to write a function can_be_composed(word1, word2) to check if word1 can be composed from word2 . Put your function into a file compose.py. Example usages: • can_be_composed("python", "pantyhose") returns True • can_be_composed("python", "ponytail") returns False • can_be_composed("code", "docent") returns True • can_be_composed("messy", "reassembly") returns True • can_be_composed("computational", "alphanumeric") returns False • can_be_composed("linguistics", "criminologists") returns False Hint: Write a function word2dict(word) which will convert word to a dictionary with an information how many times every letter occured in word . Use word2dict in your can_be_composed function.

3996 次点击
所在节点    Python
18 条回复
ipwx
2019-11-28 23:35:30 +08:00
>>> def can_be_composed(a, b):
... a_count = collections.Counter(a)
... b_count = collections.Counter(b)
... return all(a_count[k] <= b_count.get(k, 0) for k in a_count)
HHH01
2019-11-28 23:48:34 +08:00
@ipwx 厉害。。。简单几个代码就把我一堆都简化了
不多,.get(k,0)这一块不是很理解,为啥要有 0 ?
cherbim
2019-11-28 23:52:36 +08:00
你知道你为啥每次都输出 True 呢,for 循环里面,return 直接返回值,停止方法,比如第一次循环,第一个单词第一个字母如果在第二个单词里,你 return true,直接这个方法就停止了,然后返回 ture,如果没有,返回 false,后面的都没比较,修改一下:return true 要放在 for 循环外面,return flase 放在 for 循环内部 ,判断字母在不在第二个里面 ,如果不在 return flase 如果在就 pass
cherbim
2019-11-29 00:00:44 +08:00
@ryanjmliao dict.get(key, default=None) key -- 字典中要查找的键 default -- 如果指定键的值不存在时,返回该默认值 0 表示如果不存在返回 0,可以自己设定返回值
ibirdyuan
2019-11-29 00:11:28 +08:00
def can_be_composed(a, b):
if set(a) - set(b):
return False
else:
return True
ljpCN
2019-11-29 00:21:08 +08:00
@ibirdyuan 还可以写得更 Python 一点
>>> def can_be_composed(a, b):
... return False if set(a) - set(b) else True
noqwerty
2019-11-29 00:37:00 +08:00
@ibirdyuan 这样应该不行吧,原题的要求是还要有足够数量的字母,比如 a 需要两个 y 而 b 只有一个 y 的话也会返回 False
just1
2019-11-29 00:37:14 +08:00
@ljpCN #6 return bool(set(a) - set(b))
ibirdyuan
2019-11-29 00:40:11 +08:00
@noqwerty 你是对的,刚没看原题,以为就是一个判断子集的问题。
刚发现原题有一句
Similarly, word “lesson” can be composed from “professional” or “responsible”, but it can not be composed from word “longest” as “longest” does not have enough “s” letters.
festoney8
2019-11-29 01:59:10 +08:00
word2 中逐个踢掉 word1 字母
dji38838c
2019-11-29 04:41:59 +08:00
搞那么多 bool, if 的干什么,集合里难道会没有子集的 operation 吗

return set(b).issubset(set(a))
ryanccq
2019-11-29 08:24:05 +08:00
def can_be_composed(word1, word2):
return all([word1.count(i) <= word2.count(i) for i in word1])
hell0v2
2019-11-29 08:54:48 +08:00
11 楼正式我想说的,不应该是思路问题么,这种情况用什么字典。。。
yucongo
2019-11-29 12:14:51 +08:00
check = lambda x, y: all([y.count(elm) >= x.count(elm) for elm in x])

check("python", "pantyhose") # True
check('lesson', 'professional') # True
check('lesson', 'responsible') # True
check('lesson', 'longest') # False
ipwx
2019-11-29 12:22:36 +08:00
楼上一堆没审题就来逼逼用集合差的家伙。
imn1
2019-11-29 12:25:52 +08:00
我建议变量 word2dict 改名
变量和函数同名,return word2dict 这句会有问题吧?
mixure
2019-11-29 15:39:29 +08:00
我想知道 V2EX 怎么不让代码发出来乱七八糟的。

---

from doctest import testmod
def can_be_composed(word1,word2):
"""
>>> can_be_composed('lesson', 'professional')
True
>>> can_be_composed('lesson', 'longest')
False
"""
word2=list(word2)
try:
[word2.remove(word) for word in word1]
except ValueError:
return False
return True

testmod()

---

我在 Ipython 里面 用 time 试了以下,似乎比 1 楼的还快一些
yucongo
2019-11-30 00:40:31 +08:00
楼上想法不错,一行实现,好像没办法 lambda 实现

def check1(word1, word2): list2 = [*word2]; return not any([*map(lambda x: list2.remove(x) if x in list2 else True, word1)])

check('lesson', 'responsible') # True
check('lesson', 'longest') # False

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/624125

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX