2

在 Python 中,我有一个简单的转换列表和字典的问题,我使用显式类型检查解决了这个问题,以区分整数和整数列表。我对python有点陌生,我很好奇是否有更“pythonic”的方法来解决问题,即避免显式类型检查。

简而言之:尝试使用值对字典的键进行排序,但是每个键可以有多个值,并且键需要在列表中出现多次。数据以 形式出现{'a':1, 'b':[0,2],...}。我提出的所有内容(使用 sorted( , key = ) )都被以下事实绊倒了:一次出现的值不能指定为整数而不是列表 1 的长度。

我想在表单{'a':3, 'b':0, 'c':[2,4], 'd':[1,5]}和列表的字典之间进行转换['b', 'd', 'c', 'a', 'c', 'd'](列表中项目的位置由字典中的值指定)。

该函数list_to_dictionary应该为列表中出现的每个项目都有一个键,其值给出列表中的位置。如果一个项目出现不止一次,该值应该是一个存储所有这些位置的列表。

该函数dictionary_to_list应该创建一个由字典的键组成的列表,按值排序。如果该值不是单个整数而是整数列表,则该键应在相应的排序位置多次出现在列表中。

我的解决方案如下:

def dictionary_to_list(d):
"""inputs a dictionary a:i or a:[i,j], outputs a list of a sorted by i"""    
    #Converts i to [i] as value of dictionary
    for a in d:
        if type(d[a])!=type([0,1]):
            d[a] = [d[a]]

    #Reverses the dictionary from {a:[i,j]...} to {i:a, j:a,...}
    reversed_d ={i:a for a in d for i in d[a]}

    return  [x[1] for x in sorted(reversed_d.items(), key=lambda x:x[0])]

def list_to_dictionary(x):
    d = {}        
    for i in range(len(x)):
        a = x[i]            
        if a in d:
            d[a].append(i)
        else:
            d[a]=[i]
    #Creates {a:[i], b:[j,k],...}

    for a in d:
        if len(d[a])==1:
            d[a] = d[a][0]
    #Converts to {a:i, b:[j,k],...}

    return d

由于与我的其余代码的交互,我无法将问题更改为长度为 1 的列表代替单个整数作为字典的值。似乎应该有一种简单的方法来处理这个问题,但我无法弄清楚。这里更好的解决方案将有几个适用于我的 python 脚本的应用程序。

谢谢

4

3 回答 3

1
def dictionary_to_list(data):
    result = {}
    for key, value in data.items():
        if isinstance(value, list):
            for index in value:
                result[index] = key
        else:
            result[value] = key
    return [result[key] for key in sorted(result)]

def list_to_dictionary(data):
    result = {}
    for index, char in enumerate(data):
        result.setdefault(char, [])
        result[char].append(index)
    return dict((key, value[0]) if len(value) == 1 else (key, value) for key, value in result.items())

dictData = {'a':3, 'b':0, 'c':[2,4], 'd':[1,5]}
listData = ['b', 'd', 'c', 'a', 'c', 'd']

print dictionary_to_list(dictData)
print list_to_dictionary(listData)

输出

['b', 'd', 'c', 'a', 'c', 'd']
{'a': 3, 'c': [2, 4], 'b': 0, 'd': [1, 5]}
于 2013-10-30T06:23:02.280 回答
1
In [17]: d = {'a':3, 'b':0, 'c':[2,4], 'd':[1,5]}

In [18]: sorted(list(itertools.chain.from_iterable([[k]*(1 if isinstance(d[k], int) else len(d[k])) for k in d])), key=lambda i:d[i] if isinstance(d[i], int) else d[i].pop(0))
Out[18]: ['b', 'd', 'c', 'a', 'c', 'd']

呼吁是:

sorted(
  list(
    itertools.chain.from_iterable(
      [[k]*(1 if isinstance(d[k], int) else len(d[k])) 
        for k in d
      ]
    )
  ), 
  key=lambda i:d[i] if isinstance(d[i], int) else d[i].pop(0)
)

这个想法是第一部分(即list(itertools.chain.from_iterable([[k]*(1 if isinstance(d[k], int) else len(d[k])) for k in d]))在 中创建键的列表d,重复与其关联的值的数量。因此,如果键具有与其值一样的单个int(或仅包含一个的列表int),则它出现一次此列表;否则,它出现的次数与列表中的项目一样多。

接下来,我们假设对值进行了排序(否则作为预处理步骤很简单)。所以现在,我们要做的是按它们的第一个值对键进行排序。如果它们只有一个 int 作为它们的值,则考虑它;否则,列表中的第一个元素包含其所有值。第一个元素也从列表中删除(通过调用 pop),以便后续出现的相同键不会重用相同的值

如果您想在没有显式类型检查的情况下执行此操作,则可以将所有值列为预处理步骤:

In [22]: d = {'a':3, 'b':0, 'c':[2,4], 'd':[1,5]}

In [23]: d = {k:v if isinstance(v, list) else [v] for k,v in d.iteritems()}

In [24]: d
Out[24]: {'a': [3], 'b': [0], 'c': [2, 4], 'd': [1, 5]}

In [25]: sorted(list(itertools.chain.from_iterable([[k]*len(d[k]) for k in d])), key=lambda i:d[i].pop(0))
Out[25]: ['b', 'd', 'c', 'a', 'c', 'd']
于 2013-10-30T06:26:44.750 回答
0
def dictionary_to_list(d):
    return [k[0] for k in sorted(list(((key,n) for key, value in d.items() if isinstance(value, list) for n in value))+\
    [(key, value) for key, value in d.items() if not isinstance(value, list)], key=lambda k:k[1])]

def list_to_dictionary(l):
    d = {}
    for i, c in enumerate(l):
        if c in d:
            if isinstance(d[c], list):
                d[c].append(i)
            else:
                d[c] = [d[c], i]
        else:
            d[c] = i
    return d
l = dictionary_to_list({'a':3, 'b':0, 'c':[2,4], 'd':[1,5]})
print(l)
print(list_to_dictionary(l))
于 2013-10-30T06:44:53.700 回答