我正在写一个函数,用符号(如"kg")来简化分数,而不带数字(系数)。
函数接受两个实参:第一个列表包含分子中所引用的所有单位,第二个列表列出分母中所引用的单位。
我想我已经完成了大部分的功能,但是我不明白为什么它没有通过一些测试。
例如,当分母和分子相等时,它不会像预期的那样返回(['1'], ['1'])
,另一个例子是当测试中的函数返回(['1', '1', 's'], ['s'])
而不是(['1'], ['1'])
时。
我代码:
def canonical(unit):
numerador = unit[0]
denominador = unit[1]
numerador.sort()
denominador.sort()
lstNumerador = numerador
lstDenominador = denominador
for i in numerador:
for j in denominador:
if i == j:
lstNumerador.remove(i)
lstDenominador.remove(j)
if lstNumerador.count('1') > 0:
lstNumerador.remove('1')
if lstDenominador.count('1') > 0:
lstDenominador.remove('1')
if len(lstNumerador) == 0:
lstNumerador.append('1')
if len(lstDenominador) == 0:
lstDenominador.append('1')
unit = (lstNumerador, lstDenominador)
return unit
# What I expect
unit = (['kg', 'm', 'm', 's'], ['m', 's', 's'])
print(canonical(unit))
#(['kg', 'm'], ['s'])
unit = (['kg', 'm', 'm', 's'], ['s', 'm', 'm', 'kg'])
print(canonical(unit))
#(['1'], ['1'])
unit = (['s', 'kg', 'm', '1'], ['1', '1'])
print(canonical(unit))
#(['kg', 'm', 's'], ['1'])
unit = (['1', 'm', 's', '1', '1'], ['m', 's'])
print(canonical(unit))
#(['1'], ['1'])
unit = (['kg', 'm', 'm'], ['kg', 'm', 'm'])
print(canonical(unit))
#(['1'], ['1'])
# What I received instead
(['kg', 'm'], ['s'])
(['m', 's'], ['m', 's'])
(['kg', 'm', 's'], ['1'])
(['1', '1', 's'], ['s'])
(['m'], ['m'])
主要问题是您在正在迭代的列表上调用remove
。这很少是一个好主意,因为它会"拉扯地毯"。可以跳过的一些值。
其次,嵌套循环通常效率不高。使用字典可以更好地做到这一点。
这个代码挑战实际上是Counter
字典的理想候选。除了构造函数创建一个带有每个元素计数的字典之外,它还允许对两个这样的Counter对象进行减法,并使用一元操作符对Counter对象进行求反。您可以使用elements
方法轻松地再次获得单个(重复的)元素。这一切都是非常方便的,以一种有效的方式达到预期的结果。
如下所示:
from collections import Counter
def canonical(unit):
diff = Counter(unit[0])
diff.subtract(unit[1]) # May produce negative frequencies
del diff["1"] # NB: Counter objects don't raise "key error"
return list(diff.elements()) or ["1"], list((-diff).elements()) or ["1"]
见下文。我创建了你的单位的深度副本,所以它是坚不可摧的迭代/删除,并纠正了一些地方错误的逻辑。这将给出您期望的输出。
import copy
def canonical(unit):
numerador = unit[0]
denominador = unit[1]
numerador.sort()
denominador.sort()
lstNumerador = copy.deepcopy(numerador)
lstDenominador = copy.deepcopy(denominador)
for i in numerador:
for j in denominador:
if (i in lstNumerador) and (i in lstDenominador):
lstNumerador.remove(i)
lstDenominador.remove(i)
while lstNumerador.count('1') > 1:
lstNumerador.remove('1')
while lstDenominador.count('1') > 1:
lstDenominador.remove('1')
if len(lstNumerador) == 0:
lstNumerador.append('1')
if len(lstDenominador) == 0:
lstDenominador.append('1')
unit = (lstNumerador, lstDenominador)
return unit
unit1 = (['kg', 'm', 'm', 's'], ['m', 's', 's'])
unit2 = (['kg', 'm', 'm', 's'], ['s', 'm', 'm', 'kg'])
unit3 = (['s', 'kg', 'm', '1'], ['1', '1'])
unit4 = (['1', 'm', 's', '1', '1'], ['m', 's'])
unit5 = (['kg', 'm', 'm'], ['kg', 'm', 'm'])
units = [unit1, unit2, unit3, unit4, unit5]
for entry in units:
print(canonical(entry))
输出:
(['kg', 'm'], ['s'])
(['1'], ['1'])
(['kg', 'm', 's'], ['1'])
(['1'], ['1'])
(['1'], ['1'])
注意:我没有给分母加1,而是留了个空
def canonical(unit):
numerador = sorted([i for i in unit[0] if i!='1'])
denominador = sorted([i for i in unit[1] if i!='1'])
numCount= {i : numerador.count(i)-denominador.count(i) for i in set(numerador +denominador)}
numerador=[]
denominador= []
for num,count in numCount.items():
if count>0:
numerador+=[num]*count
elif count<0:
denominador+= [num]*-count
if len(numerador) == 0:
numerador=['1']
if len(denominador) == 0:
denominador=['1']
return (numerador, denominador)