ChatGPT解决这个技术问题 Extra ChatGPT

列表理解中的 if/else

如何将所有 None 替换为空字符串,然后调用某个函数 f

[f(x) for x in xs if x is not None else '']
另请参阅 stackoverflow.com/questions/24442091 了解相反的问题。

M
Mateen Ulhaq

你完全可以做到这一点。这只是一个订购问题:

[f(x) if x is not None else '' for x in xs]

一般来说,

[f(x) if condition else g(x) for x in sequence]

而且,对于仅具有 if 条件的列表推导,

[f(x) for x in sequence if condition]

请注意,这实际上使用了不同的语言结构,即 conditional expression,它本身不是 comprehension syntax 的一部分,而 for…in 之后的 if 是列表解析的一部分并用于过滤 来自源迭代的元素。

条件表达式可用于您希望根据某些条件在两个表达式值之间进行选择的各种情况。这与 ternary operator ?: that exists in other languages 的作用相同。例如:

value = 123
print(value, 'is', 'even' if value % 2 == 0 else 'odd')

这就是为什么我更喜欢将三元运算符放在括号中,这样可以更清楚地表明它只是一个普通的表达式,而不是一个推导式。
所以诀窍是“在列表压缩中我写了 if before for then 我必须添加 else 部分”。因为如果我的 l = [ 2, 3, 4, 5] 然后 [x if x % 2 == 0 for x in l] 给我错误,而 [x if x % 2 == 0 else 200 for x in l] 有效。是的,我知道过滤它我应该写 [ x for x in l if x % 2 == 0]。打扰了。感谢您的回答。
python docs mention the ternary operator。请注意,它需要else,否则它不起作用。
示例:[x for x in range(50) if (x%3)==0] 将返回可被 3 整除的整数列表。[x if (x%3)==0 for x in range(50)] 无效,因为 x if (x%3)==0 不是有效表达式。 @Grijesh,这是您规则的反例(如果之前/之后):[x for x in range(50) if ((x%3)==0 if x>20 else False)]。此推导式的过滤条件将仅匹配可被 3 整除且大于 20 的整数。
@Drewdin 列表推导不支持在迭代期间中断。那么你将不得不使用一个正常的循环。
T
Tim Skov Jacobsen

具体问题已经在之前的答案中解决了,所以我将讨论在列表推导中使用条件的一般想法。

这是一个示例,显示了如何在列表推导中编写条件:

X = [1.5, 2.3, 4.4, 5.4, 'n', 1.5, 5.1, 'a']     # Original list

# Extract non-strings from X to new list
X_non_str = [el for el in X if not isinstance(el, str)]  # When using only 'if', put 'for' in the beginning

# Change all strings in X to 'b', preserve everything else as is
X_str_changed = ['b' if isinstance(el, str) else el for el in X]  # When using 'if' and 'else', put 'for' in the end

请注意,在 X_non_str 的第一个列表推导中,顺序为:

可迭代 if 条件中的项目表达式

X_str_changed 的最后一个列表推导中,顺序为:

表达式 1 if 条件 else 表达式 2 用于迭代中的项目

我总是觉得很难记住 expression1 必须在 if 之前,而 expression2 必须在 else 之后。我的头脑希望两者都在之前或之后。

我猜它是这样设计的,因为它类似于普通语言,例如“如果下雨我想呆在里面,否则我想出去”

用简单的英语来说,上面提到的两种类型的列表理解可以表述为:

只有 if

如果 apple_is_ripe,则为 apple_box 中的苹果提取苹果

if/else

mark_apple if apple_is_ripe else leave_it_unmarked for apple in apple_box


你可以两者兼得。例如,这个 Buzzless Fizzbuzz: vals = list(range(40)); [val if val % 3 else "Fizz" for val in vals if val % 5] 结合了结果列表中内容的表达式和过滤条件。
M
Mateen Ulhaq

让我们用这个问题来回顾一些概念。我认为首先了解基本面是很好的,这样您就可以推断出不同的情况。

其他答案为您的问题提供了具体答案。我将首先给出一些一般背景,然后我会回答这个问题。

基础知识

if/else 列表推导中的语句涉及两件事:

列表推导

条件表达式(三元运算符)

1. 列表推导

它们provide是创建列表的简洁方式。

它的结构包括:“包含一个表达式的括号,后跟一个 for 子句,然后是零个或多个 for 或 if 子句”。

情况1

我们这里没有条件。可迭代的每个项目都添加到 new_list

new_list = [expression for item in iterable]
new_list = [x for x in range(1, 10)]
> [1, 2, 3, 4, 5, 6, 7, 8, 9]

案例2

这里我们有一个条件。

示例 1

条件:只有 偶数 个数字会添加到 new_list

new_list = [expression for item in iterable if condition == True]
new_list = [x for x in range(1, 10) if x % 2 == 0]
> [2, 4, 6, 8]

示例 2

条件:只有 偶数 个 3 的倍数会被添加到 new_list

new_list = [expression for item in iterable if condition == True]
new_list = [x for x in range(1, 10) if x % 2 == 0 if x % 3 == 0]
> [6]

但是如果我们在 new_list 中使用两个 if,我们怎么会有一个条件呢?

前面的表达式可以写成:

new_list = [x for x in range(1, 10) if x % 2 and x % 3 == 0]
> [6]

我们只使用一个 if 语句。

这就像做:

new_list = []
for x in range(1, 10):
    if x % 2 == 0 and x % 3 == 0:
        new_list.append(x)
> [6]

示例 3

只是为了论证,您也可以使用 or

条件:偶数个数字或3的倍数将被添加到new_list

new_list = [x for x in range(1, 10) if x % 2 == 0 or x % 3 == 0]
> [2, 3, 4, 6, 8, 9]

案例3

不止一种情况:

这里我们需要条件表达式(三元运算符)的帮助。

2.条件表达式

什么是条件表达式?顾名思义:一个有条件的 Python 表达式。

<Exp1> if condition else <Exp2>

首先评估 condition。如果 conditionTrue,则计算并返回 <Exp1>。如果 conditionFalse,则计算并返回 <Exp2>

具有多个条件的条件表达式:

<Exp1> if condition else <Exp2> if condition else <Exp3>...    

Real Python 中的示例:

age = 12
s = 'minor' if age < 21 else 'adult'
> minor

s 的值以 age 值为条件。

3.List Compresions with Conditionals

我们像这样将列表推导式和条件式放在一起。

new_list = [<Conditional Expression> for <item> in <iterable>]

new_list = [<Exp1> if condition else <Exp2> if condition else <Exp3> for <item> in <iterable>]

条件:偶数个加成'even',数字3加成'number three',其余加成'odd'

new_list = ['even' if x % 2 == 0 else 'number three' if x == 3 else 'odd' 
             for x in range(1, 10)]
> ['odd', 'even', 'number three', 'even', 'odd', 'even', 'odd', 'even', 'odd']

问题的答案

[f(x) for x in xs if x is not None else '']

这里我们遇到了列表结构的问题:for x in xs 应该在表达式的末尾。

正确方法:

[f(x) if x is not None else '' for x in xs]

进一步阅读:

Does Python have a ternary conditional operator?


到目前为止,这是我在这里和其他地方能找到的最佳答案。非常感谢Guzman Ojero先生
M
Mateen Ulhaq

单程:

def change(x):
    if x is None:
        return f(x)
    else:
        return ''

result = [change(x) for x in xs]

虽然那时你有:

result = map(change, xs)

或者您可以使用 lambda 内联。


当您必须处理来自其或 else 语句块中的 if 表达式或代码的可能异常时,这也是一种很好的(也许是唯一的)技术。对于简单的情况,接受的答案更好。
B
Bengt

这是另一个说明性示例:

>>> print(", ".join(["ha" if i else "Ha" for i in range(3)]) + "!")
Ha, ha, ha!

它利用了这样一个事实:对于 0if i 的计算结果为 False,对于函数 range() 生成的所有其他值,则为 True。因此,列表推导式评估如下:

>>> ["ha" if i else "Ha" for i in range(3)]
['Ha', 'ha', 'ha']

M
Mateen Ulhaq

其他解决方案非常适合单个 if / else 构造。然而,列表推导式中的三元语句可能很难阅读。

使用函数有助于提高可读性,但这样的解决方案很难在映射为输入的工作流中扩展或调整。字典可以缓解这些担忧:

xs = [None, 'This', 'is', 'a', 'filler', 'test', 'string', None]

d = {None: '', 'filler': 'manipulated'}

res = [d.get(x, x) for x in xs]

print(res)

['', 'This', 'is', 'a', 'manipulated', 'test', 'string', '']

a
arboc7

它与列表理解的执行方式有关。

请记住以下几点:

[ expression for item in list if conditional ]

相当于:

for item in list:
    if conditional:
        expression

expression 的格式略有不同(考虑在句子中切换主语和动词顺序)。

因此,您的代码 [x+1 for x in l if x >= 45] 执行此操作:

for x in l:
    if x >= 45:
        x+1

但是,此代码 [x+1 if x >= 45 else x+5 for x in l] 执行此操作(在重新排列 expression 之后):

for x in l:
    if x>=45: x+1
    else: x+5

M
Mateen Ulhaq
[f(x) if x != None else '' for x in xs]

列表理解的语法:

[item if condition else item for item in items]
[f(item) if condition else value for item in items]
[item if condition for item in items]
[value if condition else value1 if condition1 else value2]

这似乎是最佳答案的重复,对列表理解进行了一些澄清。
好像您忘记了“for”[value if condition else value1 if condition1 else value2]
P
Peter Mortensen

从可迭代的项目中创建列表

似乎最好先概括所有可能的形式,而不是给出问题的具体答案。否则,读者将不知道答案是如何确定的。这是我在头疼之前想出的一些通用形式,试图决定是否可以在最后一种形式中使用最后的 else 子句。

[expression1(item)                                        for item in iterable]

[expression1(item) if conditional1                        for item in iterable]

[expression1(item) if conditional1 else expression2(item) for item in iterable]

[expression1(item) if conditional1 else expression2(item) for item in iterable if conditional2]

item 的值不需要在任何条件子句中使用。 conditional3 可用作向输出列表添加或不添加值的开关。

例如,要创建一个从原始字符串列表中删除空字符串或空白字符串的新列表:

newlist = [s for s in firstlist if s.strip()]

第二个在他的评论中给出了一个错误,因为 Tim answered,另请参阅 python 文档中的 conditional statements。这对我来说是非常难以理解的。摘要:只允许使用 this if condition else that 或普通表达式。不是 value = this if condition(可以通过 value = this if condition else None 实现)
P
Peter Mortensen

不需要三元 if/then/else。在我看来,您的问题需要这个答案:

row = [unicode((x or '').strip()) for x in row]

M
Max Kleiner

您可以在理解中结合条件逻辑:

 ps = PorterStemmer()
 stop_words_english = stopwords.words('english')
 best = sorted(word_scores.items(), key=lambda x: x[1], reverse=True)[:10000]
 bestwords = set([w for w, s in best])


 def best_word_feats(words):
   return dict([(word, True) for word in words if word in bestwords])

 # with stemmer
 def best_word_feats_stem(words):
   return dict([(ps.stem(word), True) for word in words if word in bestwords])

 # with stemmer and not stopwords
 def best_word_feats_stem_stop(words):
   return dict([(ps.stem(word), True) for word in words if word in bestwords and word not in stop_words_english])

T
Trop Freshloïc
# coding=utf-8

def my_function_get_list():
    my_list = [0, 1, 2, 3, 4, 5]

    # You may use map() to convert each item in the list to a string, 
    # and then join them to print my_list

    print("Affichage de my_list [{0}]".format(', '.join(map(str, my_list))))

    return my_list


my_result_list = [
   (
       number_in_my_list + 4,  # Condition is False : append number_in_my_list + 4 in my_result_list
       number_in_my_list * 2  # Condition is True : append number_in_my_list * 2 in my_result_list
   )

   [number_in_my_list % 2 == 0]  # [Condition] If the number in my list is even

   for number_in_my_list in my_function_get_list()  # For each number in my list
]

print("Affichage de my_result_list [{0}]".format(', '.join(map(str, my_result_list))))

(venv) $ python list_comp.py 附上 my_list [0, 1, 2, 3, 4, 5] 附上 my_result_list [0, 5, 4, 7, 8, 9]

因此,对您而言:row = [('', unicode(x.strip()))[x is not None] for x in row]


"Affichage de..." 是什么意思?是法语吗?
@PeterMortensen 确实是法语,意思是“显示/概述”。所以Displaying / overview of my_result_list