Python - 使用字典来计算键和值

时间:2016-04-16 20:47:04

标签: python dictionary keyvaluepair

我是python课程的学生,我们创建了一个元组列表(包含2个元素),我们试图以各种方式操作它们。此外,我们将这些元组元素转换为字典,并使用字典重新创建操作并避免循环。我坚持的任务是,给定一个特定的id(可能是字典中的一个键OR值),该函数返回在该字典中找到的所有其他键/值。

为此使用字典似乎并不高效,但这是我们在课程中所处的部分,并且具体由作业提出。对于循环也没有(如果可能的话?)。回想一下,id可以是字典中的键或值。

example_dictionary = {'A': 'C', 'R': 'E', 'D': 'A', 'L': 'R', 'C': 'D'}

def get_interactions(example_dictionary, id):
    output = ''
    for j,k in example_dictionary.items():
        if j == id:
            output = output + k + ' '
        if k == id:
            output = output + j + ' '
    return output

这段代码工作得很好,但它1)有一个for循环(没有好处)和2)不是非常pythonic(有点像眼睛)!我怎样才能更有效地使用字典并压缩我的字符串呢?我在Python 3中,谢谢!

4 个答案:

答案 0 :(得分:0)

你可以使用列表推导,虽然有人可能会认为它是一种for循环:

example_dictionary = {'A': 'C', 'R': 'E', 'D': 'A', 'L': 'R', 'C': 'D'}   
def get_interactions(dic, id):
    output =[v for k, v in dic.items() if k == id] + [k for k,v in dic.items() if v == id]
    return output

答案 1 :(得分:0)

我不知道如何避免使用for循环,而不是制作自己的for循环,类似于以下内容:

i = 0
def func(tup, id) {
    if i < len(dictionary_items):        
        output = False

        if tup[0] == id or tup[1] == id:
            output = id + ' '

        i += 1

        return output
}

dictionary_items = dictionary.items()

func(dictionary_items[0], id)
func(dictionary_items[1], id)
func(dictionary_items[2], id)

等等。然而,这将是丑陋的,非常非pythonic。

至于使代码更加pythonic,您可以将行output = output + k + ' '更改为output += k + ' 'output = k + ' '(您可以将字符串k和&#39;&#39连接起来;输出一个空字符串,它不会改变字符串k和&#39;) 此外,你可以检查if j == id or k == id而不是两个单独的if语句,然后说output = id + ' ',因为如果j或k等于id,如果你返回j和k中的任何一个并不重要等于id或者如果你返回id本身。

答案 2 :(得分:0)

您必须检查所有键和值,因此总会出现某种类型的循环。 Python有许多方法可以在没有明确使用for的情况下迭代(即循环)项目。

在没有for的情况下迭代项目的一种好方法是使用filtermapreduce内置函数以及lambda语法用于创建小型匿名函数。

from itertools import chain

# Get values for matching keys and vice versa
values = map(lambda x: x[1] if x[0] == id else None, dct.items())
keys = map(lambda x: x[0] if x[1] == id else None, dct.items())

# Then you filter out the None values 
# itertools.chain allows us to conveniently do this in one line
matches = filter(lambda x: x is not None, chain(keys, values))

如果您无法使用itertools.chain,则只需要一些额外的步骤

keys = filter(lambda x: x is not None, keys)
values = filter(lambda x: x is not None, values)
matches = keys + values

如果您需要以空格分隔的值输出:

output = ' '.join(matches)

答案 3 :(得分:0)

预期结果

有一个字典和名为wanted的值,您想要创建另一个字典作为副本 原始的一个删除了没有键或值等于wanted值的所有项目。

它可以用几个场景的pytest测试用例的形式表示。

import pytest
scenarios = [
    [
        # dct
        {'A': 'C', 'R': 'E', 'D': 'A', 'L': 'R', 'C': 'D'},
        # wanted
        "A",
        # expected (result)
        {'A': 'C', 'D': 'A'},
    ],
    [
        # dct
        {'A': 'C', 'R': 'E', 'D': 'A', 'L': 'R', 'C': 'D'},
        # wanted
        "E",
        # expected (result)
        {'R': 'E'},
    ],
    [
        # dct
        {'A': 'C', 'R': 'E', 'D': 'A', 'L': 'R', 'C': 'D'},
        # wanted
        "D",
        # expected (result)
        {'D': 'A', 'C': 'D'},
    ],
    [
        # dct
        {'A': 'C', 'R': 'E', 'D': 'A', 'L': 'R', 'C': 'D'},
        # wanted
        "nothere",
        # expected (result)
        {},
    ],
    [
        # dct
        {'A': 'C', 'R': 'E', 'D': 'A', 'L': 'R', 'C': 'D'},
        # wanted
        "A",
        # expected (result)
        {'A': 'C', 'D': 'A'},
    ],
]


# replace with real implementation
def get_key_or_val_itms(dct, wanted):
    # something comes here
    return result

@pytest.mark.parametrize("scenario", scenarios)
def test_it(scenario):
    dct, wanted, expected = scenario
    assert get_key_or_val_itms(dct, wanted) == expected

除了scenarios之外,不要打扰任何事情。它列出了几个带输入的测试场景 字典,wanted的值和预期结果。

为解决方案构建石头

dict.items() - dict到元组列表

>>>  dct = {'A': 'C', 'R': 'E', 'D': 'A', 'L': 'R', 'C': 'D'}
>>>  dct.items()
[('A', 'C'), ('R', 'E'), ('D', 'A'), ('L', 'R'), ('C', 'D')]

测试元组/列表中值的成员资格

>>> 'A'  in ('A', 'C')
True
>>> 'A'  in ('R', 'E')
False

Lambda函数测试,如果元组中存在wanted

lambda允许“就地”功能定义。它经常用在地方, 其中一些函数需要引用函数。

首先,创建命名函数tuple_wanted

>>> wanted = "A"
>>> def tuple_wanted(tpl):
...    return wanted in tpl

并对其进行测试(注意,wanted现在具有值“A”):

>>> tuple_wanted(('A', 'C'))
True
>>> tuple_wanted(('R', 'E'))
False

现在创建该功能。要使用它,我们会将lambda的结果存储在fun

>>> fun = lambda tpl: wanted in tpl

它可以在tuple_wanted之前以相同的方式使用:

>>> fun(('A', 'C'))
True
>>> fun(('R', 'E'))
False

稍后我们将直接使用lambda的结果(请参阅filter) 将其存储到任何变量中。

filter删除未通过某些测试的所有列表项

filter获取测试函数和可迭代(例如项目列表)以进行测试。

调用filter的结果是来自iterable的项目列表,它通过了测试。

在我们的例子中,我们只希望传递包含wanted值的元组(例如“A”)

>>> filter(tuple_wanted, dct.items())
    [('A', 'C'), ('D', 'A')]
>>> filter(fun, dct.items())
    [('A', 'C'), ('D', 'A')]
>>> filter(lambda tpl: wanted in tpl, dct.items())
    [('A', 'C'), ('D', 'A')]

将包含2个项目的元组列表转换为字典

>>> tpllst = [('A', 'C'), ('D', 'A')]
>>> dict(tpllst)
    {'A': 'C', 'D': 'A'}

完成工作的功能

长版

此版本用于解释一步一步的内容:

def get_key_or_val_itms(dct, wanted):
    # dict as [(key, val), (key2, val2), ...]
    tpldct = dct.items()
    # find tuples, where either key or val equals `wanted` value
    # first make function, which detects, the tuple we search for

    def tuple_wanted(tpl):
        return wanted in tpl
    # now use it to filter only what we search for
    restpldct = filter(tuple_wanted, tpldct)
    # finally, turn the result into dict
    return dict(restpldct)

短版

def get_key_or_val_itms(dct, wanted):
    return dict(filter(lambda tpl: wanted in tpl, dct.items()))

结论

它有效(使用该函数的长版本或短版本):

>>> dct = {'A': 'C', 'R': 'E', 'D': 'A', 'L': 'R', 'C': 'D'}
>>> wanted = "A"
>>> get_key_or_val_itms(dct, wanted)
{'A': 'C', 'D': 'A'}

如果您将该函数放入带有测试套件的文件中,则调用$ py.test -sv the_file.py将输出:

$ py.test -sv the_file.py
py.test================================ test session starts =========================
=======
platform linux2 -- Python 2.7.9, pytest-2.8.7, py-1.4.31, pluggy-0.3.1 -- /home/javl/
.virtualenvs/stack/bin/python2
cachedir: .cache
rootdir: /home/javl/sandbox/stack/dict, inifile:
collected 5 items

countdict.py::test_it[scenario0] PASSED
countdict.py::test_it[scenario1] PASSED
countdict.py::test_it[scenario2] PASSED
countdict.py::test_it[scenario3] PASSED
countdict.py::test_it[scenario4] PASSED

============================= 5 passed in 0.01 seconds ==============================

可以看出,所有情景都在过去。

解释py.test的工作方式超出了此答案的范围,要了解详情,请参阅http://pytest.org/latest/