对任意数量的字典和数字进行数学运算。

3

我想要做以下事情:

  • 接受任意数量的参数,可以是字典或数字
  • 如果有多个字典参数,检查它们是否具有相同的键(否则会出现错误)
  • 执行类似下面的操作
    for key in dict:
            out[key] = product(dict1[key],number2,dict2[key],etc.)

如果一个参数是一个数字,它会假装'好像'它是一个将该数字作为每个键的值的字典。(当然,这也可以是sum而不是product)。

理想情况下,这应该是一个库,但我可以使用手写函数。到目前为止,我还没有能够编写出适用于超过两个参数的任何东西。

例如,假设我的输入是:

a = {
    'Burkina' : 100,
    'Chad': 50
}

b = 2

对于两个参数,我认为这个方法可行:

def p(a,b):
    out = {}
    try:
        for key in a:
            try:
                out[key] = a[key]*b[key]
            except TypeError:
                out[key] = a[key]*b
    except TypeError:
        for key in b:
            try:
                out[key] = a[key]*b[key]
            except TypeError:
                out[key] = a*b[key]
    for key in out:
        print(key,out[key])

但是这种方法需要一个越来越长的函数来处理更多的参数,所以这不可能是正确的。然后我尝试使用*args进行处理:

def p(*args):
    out = {}
    for arg in args:
        try:
            for key in arg:
                try:
                    out[key] = a[key]*b[key]
                except TypeError:
                    out[key] = a[key]*b
        except TypeError:
            for key in args:
                try:
                    out[key] = a[key]*b[key]
                except TypeError:
                    out[key] = a*b[key]
        for key in out:
            print(key,out[key])

但是这样会得到TypeError,我的脑袋开始转。

添加编辑:如果所有输入都是数字,我希望返回一个数字。

谢谢!

2个回答

0

这是一个使用Python的“函数式”工具来实现的版本。

实际的乘法运算使用functools.reduce完成,使用operator.mul作为乘法运算符。如果您希望该函数执行其他操作,可以轻松地将其替换为operator模块中的另一个运算符。

需要注意以下几点:

  • 该函数通过用所有键等于非字典参数的字典替换非字典参数来处理非字典参数。如果您计划处理非常大的字典,或带有大量非字典项的参数列表,则可能会出现问题。

  • 该函数构建了其参数和参数字典的列表;同样,这对于非常大的输入可能会有问题。

  • 它没有检查参数是否全部是可接受的类型。
import functools
import operator


def p(*args):
    args = list(args)
    dicts = list(filter(lambda x: isinstance(x, dict), args))
    if not dicts:
        # Either there are no arguments, or they all numbers.
        return functools.reduce(operator.mul, args, 0)
    keys = dicts[0].keys()
    if not all(d.keys() == keys for d in dicts):
        raise ValueError(f'Not all dicts have matching keys.')
    for i, arg in enumerate(args):
        # Assume "number" means int or float, but could be complex, or Decimal?
        # See the numbers module for numeric abstract base classes.
        if isinstance(arg, (float, int)):
            args[i] = dict.fromkeys(keys, arg)
    out = {k: functools.reduce(operator.mul, (a[k] for a in args)) for k in keys}
    return out


0
最好使用isinstance而不是处理异常来检查参数是否为数字或字典:
def func(*args):
    out = {}
    factor = 1
    for arg in args:
        if isinstance(arg, dict):
            if not out:
                out = arg.copy()
            elif out.keys() != arg.keys():
                raise KeyError('not same keys')
            else:
                for key in out:
                    out[key] *= arg[key]
        else:
            factor *= arg
    for key in out:
        out[key] *= factor
    if out:
        return out
    return factor


print(
    func(
        {'key1': 1, 'key2': 2},
        3,
        {'key1': 10, 'key2': 20},
        4
    )
)

print(func(2, 3))

# result:
# {'key1': 120, 'key2': 480}
# 6

很好,但是假设输入参数列表中至少有一个字典。我不知道这是否是问题遗漏的保证。但是,func(2, 3)返回{},而不是6。 - DarrylG
@DarrylG func 被编写成始终返回字典。从 func(2, 3) 返回 6 可能会在使用此函数的“客户端”上引起问题。 - sanyassh
假设至少有一个字典是发帖者忽略的假设。或者,发帖者需要指定在func(2, 3)的边缘情况下他期望返回什么。 - DarrylG
不错的观点,DarrylG。如果所有输入都是数字,我想返回一个数字。 - tmkadamcz
@tmksitt 我编辑了我的答案,所以如果参数中没有字典,则该函数返回数字。 - sanyassh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接