python 3字典理解:高级

时间:2018-04-04 01:19:07

标签: python list-comprehension

是否可以将其转换为字典理解?我怎么知道呢 什么可以转换,什么不可以?

console

2 个答案:

答案 0 :(得分:2)

事实上,你可以使用词典理解,但你不应该。如果你准备好了,我们走了。

我将首先对您的代码进行一些清理。

首先,我将cpPtr.split(" ")[0]cpPtr.split(" ")[1]替换为uv,其中u,v = cpPtr.split(" ")。这是一个解构分配。

然后我内联以下几行:

if domainKey in domainAggregator.keys():
    domainAggregator[domainKey] = int(domainAggregator[domainKey]) + int(u)
else:
    domainAggregator[domainKey] = int(u)

成:

domainAggregator[domainKey] = int(domainAggregator[domainKey])+int(u) if domainKey in domainAggregator.keys() else int(u)

我现在得到以下代码:

for cpPtr in cpdomains:
    u,v = cpPtr.split(" ")
    for domainKey in self.domainSplitter(v):
        domainAggregator[domainKey] =  int(domainAggregator[domainKey])+int(u) if domainKey in domainAggregator.keys() else int(u)

我希望将其转化为字典理解。

现在,有些小黑客。

您不能在列表或词典理解中使用分配。为了把它放在列表理解中(然后是dict理解,见后面),我需要摆脱= s:

u, v = cpPtr.split(" ")
...
    domainAggregator[domainKey] =  int(domainAggregator[domainKey])+int(u) if domainKey in domainAggregator.keys() else int(u)

变为:

for u, v in [cpPtr.split(" ")]: # this is a singleton
    ...
    domainAggregator.update({domainKey:int(domainAggregator[domainKey])+int(u) if domainKey in domainAggregator.keys() else int(u)}) # I update the dict

代码现在是:

for cpPtr in cpdomains:
    for u,v in [cpPtr.split(" ")]:
        for domainKey in self.domainSplitter(v):
            domainAggregator.update({domainKey:int(domainAggregator[domainKey])+int(u) if domainKey in domainAggregator.keys() else int(u)})

现在,我可以使用列表推导来创建副作用。你只需要在方括号内插入所有内容:

[domainAggregator.update({domainKey:int(domainAggregator[domainKey])+int(u) if domainKey in domainAggregator.keys() else int(u)}) for cpPtr in cpdomains for u,v in [cpPtr.split(" ")] for domainKey in self.domainSplitter(v)]

好的,在评估此表达式后,domainAggregator具有预期值,但该列表只是None的列表,因为dict.update返回None

以下代码完全是疯了。不要试图在家里这样做!!!

是否可以创建一个返回正确值的字典理解?是!你必须在dict理解中创建副作用。我们试试这个:

# does not work
{k:v for k, v in domainAggregator if len( [domainAggregator.update({domainKey:(int(domainAggregator[domainKey]) if domainKey in domainAggregator.keys() else 0) + int(u)}) for cpPtr in cpdomains for u,v in [cpPtr.split(" ")] for domainKey in self.domainSplitter(v)])>=0}

表达式:

len([domainAggregator.update({domainKey:(int(domainAggregator[domainKey]) if domainKey in domainAggregator.keys() else 0) + int(u)}) for cpPtr in cpdomains for u,v in [cpPtr.split(" ")] for domainKey in self.domainSplitter(v))>=0

总是True,您有所需的副作用。但是每次迭代这些项目时都会执行这种副作用,并且你会得到臭名昭着的RuntimeError: dictionary changed size during iteration

为避免这种情况,您只需触发一次副作用。

{k:v for da in [domainAggregator for _ in range(1) if len ([domainAggregator.update({domainKey:(int(domainAggregator[domainKey]) if domainKey in domainAggregator.keys() else 0) + int(u)}) for cpPtr in cpdomains for u,v in [cpPtr.split(" ")] for domainKey in self.domainSplitter(v)])>=0] for k,v in da.items()}

内部列表触发副作用并返回字典,外部字典理解遍历项目并创建字典。

不要这样做!!!

MVCE:Try it online!

答案 1 :(得分:1)

由于我在评论中解释的原因,我们无法真正将其转化为词典理解,但我们当然可以简化您所拥有的内容。使用$from = DB::table('sell_data')->select('vd_id')->selectRaw('count(vd_id) subCount') ->groupBy('vd_id'); $results = DB::query() ->select('vd_id', 'subCount') ->fromSub($from, 'sub') ->where('subCount', function($query) { $query->selectRaw('count(vd_id) maxCount') ->from('sell_data') ->groupBy('vd_id') ->orderByDesc('maxCount') ->limit(1); }) ->orWhere('subCount', function($query) { $query->selectRaw('count(vd_id) minCount') ->from('sell_data') ->groupBy('vd_id') ->orderBy('minCount') ->limit(1); }) ->get(); 访问get()元素,如果密钥不存在,我们可以提供默认值domainAggregator,从而消除0语句。

if