将词典列表转换为一组词典

时间:2019-11-15 13:58:57

标签: python dictionary set

我有一个字典列表,如下所示:

while IFS= read -r -d $'\0' file; do
        if ! lsof -f -- "$file" > /dev/null 2>&1; then
            if [ "$_BATCH_RUN" == true ]; then
                Logger "Preparing to process [$file]." "NOTICE"
            fi
            OCR "$file" "$fileExtension" "$ocrEngineArgs" "$csvHack"
        else
            if [ "$_BATCH_RUN" == true ]; then
                Logger "Cannot process file [$file] currently in use." "ALWAYS"
            else
                Logger "Deferring file [$file] currently being written to." "ALWAYS"
                kill -USR1 $SCRIPT_PID
            fi
        fi
    done < <(find "$directoryToProcess" -type f -iregex ".*\.$FILES_TO_PROCES" ! -name "$findExcludes" -and ! -wholename "$moveSuccessExclude" -and ! -wholename "$moveFailureExclude" -and ! -name "$failedFindExcludes" -print0)

我可能会想到这个错误,但是我正在将该字典列表与另一个字典列表进行比较,并试图删除其中一个列表中的元素(字典)。为了列出操作,我想将它们都转换为集合并执行集合减法。但是,尝试进行转换时出现以下错误。

 a = [{1000976: 975},
 {1000977: 976},
 {1000978: 977},
 {1000979: 978},
 {1000980: 979},
 {1000981: 980},
 {1000982: 981},
 {1000983: 982},
 {1000984: 983},
 {1000985: 984}]

我是不是在想这个错误?

3 个答案:

答案 0 :(得分:3)

尝试一下:

>>> a = [{1000976: 975},
...  {1000977: 976},
...  {1000978: 977},
...  {1000979: 978},
...  {1000980: 979},
...  {1000981: 980},
...  {1000982: 981},
...  {1000983: 982},
...  {1000984: 983},
...  {1000985: 984}]
>>> a.extend(a)  # just to add some duplicates
>>> len(a)
20
>>> dict_set = set(frozenset(d.items()) for d in a)
>>> b = [dict(s) for s in dict_set]
>>> b
[{1000982: 981}, {1000983: 982}, {1000981: 980}, {1000985: 984}, {1000978: 977}, {1000980: 979}, {1000977: 976}, {1000976: 975}, {1000984: 983}, {1000979: 978}]
>>> len(b)
10

如果要在两个字典列表之间进行减法运算,则只需对两个字典使用与上述相同的转换集,就可以进行减法运算,然后再转换回去。

注意:至少,字典中的所有值也应该是可散列的(以及键,但这不言而喻)。如果不是这样,则需要对值进行类似的转换,将其转换为某种可哈希的,不可变的类型。

注意:这也不保留原始顺序;如果这对您很重要,则需要将其调整为适用于this one之类的算法。不过,关键是将字典转换为某种不可变的类型。

答案 1 :(得分:1)

您可以将字典变成元组,因为只有两个这样的值:

a_set = set(t for d in a for t in d.items())

然后使用set操作从该点比较两个集合。要将其转换回词典列表,可以使用:

a_list = [{key: value} for key, value in a_set]

答案 2 :(得分:1)

要进行过滤,需要使用一根衬里。 (b是字典的过滤器列表)。到目前为止,这是最快的方法,除非您针对多个集合使用相同的过滤器。

c = [a[i] for i,j in enumerate(a) if j not in b]

或使用内置过滤器:另一种(较慢)的衬里:

c = list(filter(lambda i: i not in b, a))

如果您真的要问如何将字典列表转换为可设置操作的变量,则可以使用另一种方法:

a_set = set(map(lambda i: frozenset(i.items()), a))

再次,如果我们将“ b”作为字典列表作为过滤器

b_set = set(map(lambda i: frozenset(i.items()), b))

...,我们现在可以对它们使用设置操作:

c_set = a_set - b_set

将字典转换为集合的“冻结集”方法比使用列表理解要快25%。但是将所有内容转换为集合然后执行集合操作要比使用简单的列表理解过滤器(例如我的答案顶部的过滤器)慢得多。显然,如果要进行许多过滤,则将对象转换为不可变对象可能具有成本效益。但是在那种情况下,最好更改对象的基础数据结构,然后将整个结构转换为一个类。

如果您不想使用冻结集并且您的字典是任意的,而不是单行输入字典,则可以对这些字典进行分组处理:

a_set = set(map(lambda j: tuple(map(lambda i: tuple((i, j[i])), j)), a))

您在问题中建议不要任何嵌套循环,到目前为止,所有答案(包括我的答案)都带有“ for”(或lambda)。

当我们想使用set方法来过滤两个字典时,完全可以做到如下:

c = a.items() - b.items()

当然,如果我们希望c成为字典,则需要再次包装它:

c = dict(a.items() - b.items()

同样,对于不可变类型的列表,我们可以做同样的事情(通过将列表强制设置为集合:

x = [3, 4, 5, 6, 7]
y = [3, 2, 1, 7]
z = set(x) - set(y)

或(元组是不可变的)

x = [(3, 1), (4, 1), (5, 1), (6, 2), (7, 5)]
y = [(4, 1), (4, 2), (5, 1)]
z = set(x) - set(y)

但是(可变)列表失败(如您的命令一样):

x = [[3, 1], [4, 1], [5, 1], [6, 2], [7, 5]]
y = [[4, 1], [4, 2], [5, 1]]
z = set(x) - set(y)

>>>> TypeError: unhashable type: 'list'

这是因为它们是通过引用而不是通过值存储的,因此它们的唯一性在那时是未知的。可以通过创建一个类来处理它-但这不再使用字典列表,而您的“ for”只是被埋在了类方法中。

所以-即使lambda或函数将其隐藏,您仍需要在某处嵌套循环。

相关问题