要理解一行For循环

时间:2016-08-30 18:15:28

标签: python loops for-loop apache-spark pyspark

在阅读this问题之后,我有了这个PySpark代码:

model = KMeansModel(model.Cs[0])
first_split = split_vecs.map(lambda x: x[0])
model.computeCost(first_split)
model = KMeansModel(model.Cs[1])
second_split = split_vecs.map(lambda x: x[1])
model.computeCost(second_split)

我可以将其写入单行循环吗?或者这些循环仅限于只有一条行?

注意:我不是在寻找仅代码的答案,我想学习,所以请解释一下。 :)

这是我的悲惨尝试:

model.computeCost(split) for i in range(2): # <- the semicolon here doesn't feel right..Where to put the other lines?

编辑:

是的,我知道我可以写一个普通的,但我想了解一行代码循环。这是为了试验。你看,在读别人的时候&#39;人们的代码,我经常看到它们,我对它们感到不舒服......:/

5 个答案:

答案 0 :(得分:4)

您在该示例中所做的列表理解版本将是:

[KMeansModel(model.Cs[i]).computeCost(split_vecs.map(lambda x: x[i])) for i in range(2)]

这与以下情况没有什么不同:

results = []
for i in range(2):
    results.append(KMeansModel(model.Cs[i]).computeCost(split_vecs.map(lambda x: x[i])))

因此,对于每个i,它会将该链式表达式的返回值附加到列表中。对于这个例子,它碰巧工作,因为你的三条线可以链接在一起。您在使用computeCost()创建的对象上调用了KMeansModel(model.Cs[0])方法,其参数为split_vecs.map(lambda x: x[0])

答案 1 :(得分:2)

你可以将你拥有的三个不同的函数(KMeansModel,split_vec.map和computeCost)包装在另一个函数中,如下所示:

def master_fx(var):
    return fx_C(fx_B(fx_A(var)))

现在它看起来不错,你可以使用列表理解:

[master_fx(element) for element in range(2)]

或者一个for循环(在一行或多行上 - 它通常没有区别,除了在可读性方面。我说通常是因为当我尝试将另一个控制结构放在同一行上时,我确实遇到了错误,如在:

for i in range(2): if i%2==0: print(i)

但是,出于可读性考虑,您可能不会想要像上面一行那样的东西)

最重要的区别可能是for循环只是一个控制结构,而list comprehension是一种奇特的列表,你可以在其上定义操作。这就是为什么在像ipython这样的交互式解释器中,你必须打印for循环的输出(上面例子中的元素和i)而不是列表理解。

答案 2 :(得分:2)

您正在呼叫的内容&#34;单行循环播放&#34;实际上被称为&#34;列表理解&#34;,&#34;字典理解&#34;,或&#34; generator表达式&#34;。它们比for循环更有限,并且工作如下:

# List comprehension
result = [expression for name in iterable]
# equivalent to:
result = []
for name in iterable:
    result.append(expression)

# Dictionary comprehension
result = {key_expression: value_expression for name in iterable}
# equivalent to:
result = {}
for name in iterable:
    result[key_expression] = value_expression

# Generator expression
result = (expression for name in iterable)
# equivalent to
def anonymous_generator():
    for name in iterable:
        yield expression
result = anonymous_generator()

你可以嵌套它们,它们实际上并不需要是一条线。对于(可能没有用的)示例,列表推导可用于获取列表listA中所有可能元素对的列表以及来自词典dictB中列表的元素。 listA(换行符不是必需的,但有助于提高可读性):

pairs = [(a, b) for a in listA
                for b in dictB[a]]
# equivalent to:
pairs = []
for a in listA:
    for b in dictB[a]:
        pairs.append(a, b)

然而,它们的主要限制是你不能调用任意函数 - 你可以放置表达式的唯一地方是说什么迭代你正在使用以及输出到结果中的内容。但是,您调用的任何函数的副作用都会发生!对于你的具体情况,你不能简单地在任何一个案例中这样做,因为你不断重新分配模型,你不能在理解中做到这一点。它可能有可能扭曲到足以获得相同的效果(通过在返回正确的值之前编写作为副作用的其他函数),但在这种情况下并不值得。

答案 3 :(得分:1)

这是未经测试的,但看起来它可能适合你

computedCost = [KMeansModel(model.Cs[i]).computeCost(x[i]) for i in xrange(2)]

它的作用是在对KMeansModel()的结果执行computeCost()之后创建结果列表。 xrange for loop只返回i

的值

答案 4 :(得分:0)

不使用半结肠尝试。老实说,我不建议在生成器表达式之外使用一行语句