在Python中用另一个列表的元素替换满足某些条件的列表元素

6
假设我有这两个列表。
a=[0,1,6,4,2,8] 
b=[10,20,30,40]

我可以帮您将列表A中介于0和4之间的元素替换为列表B中的项目。
换句话说,我的输出应该是:
[10,20,6,30,40,8]

请注意,我们基本上是从列表a中删除满足某个条件的元素,并将其替换为列表b中的一个项目。 (保持b中的顺序)。
编辑:
我实际上知道在列表a中恰好有N个项目符合所施加的条件。 然后,我需要使用大小为N的另一个列表b“替换”这些项目。

1
排序是否重要?输出结果可能是 [6, 8, 10, 20, 30, 40] 吗? - scharette
排序是必要的,输出应该与所示完全一致。 - Vinayak Suresh
我知道列表a中恰好有N个项目满足所施加的条件。然后我需要用另一个大小为N的列表b“替换”它们。 - Vinayak Suresh
6个回答

5

根据您的编辑,我建议使用这个简单易懂的for循环。

a=[0,1,6,4,2,8] 
b=[10,20,30,40]
upper_bound = 4
lower_bound = 0
exclusions = range(lower_bound,upper_bound+1)

for index,item in enumerate(a):
  if item in exclusions:
    a[index] = b.pop(0)

print(a)
>>>>[10, 20, 6, 30, 40, 8]

基本上,我在迭代a列表的副本,并且一旦我在指定范围内找到一个项目,就会弹出b的第一个元素并将其反馈给a

重要提示

重要的是要理解我使用了一个exclusions列表,我同意在您的特定情况下可以省略它,以允许某人向列表中添加string对象并仍然具有相同的行为方式。显然,您可以使用类似于以下内容的东西,

if item > lower_bound and item < upper_bound

针对您的特定情况,哪种方法更有效,因为您不需要创建一个不必要的列表。


回答@Julian的疑虑,假设您的列表变成了string对象,

a=['a','b','c','d','e','f'] 
b=['test','test','test','test']

而不是将0替换为4,您想要将c替换为f。使用我的解决方案,它会像这样进行:

exclusions = ['c','d','e','f']

for index,item in enumerate(a):
    if item in exclusions:
    a[index] = b.pop(0)

print(a)
>>>>['a', 'b', 'test', 'test', 'test', 'test']

根据 @Julian 的回答,

b_iter = iter(b)
print([item if item < 0 or item > 4 else b_iter.next() for item in a])
>>>> TypeError: '<' not supported between instances of 'str' and 'int'

现在他所说的,>< 操作符可以用来比较两个字符串,所以我是说他可以将比较改为string类型。
b_iter = iter(b)
print([item if item < '0' or item > '4' else b_iter.next() for item in a])
>>>>['a', 'b', 'c', 'd', 'e', 'f']

即使这样做,也是完全错误的,因为在OP的问题背景下,除了intfloat之外,比较其他对象使用<>是没有意义的。

当您使用其他类型时,这一点变得更加明显,

a=[{1,2},{2,3},{3,4},{4,5},{5,6},{6,7}] 
b=[{'test'},{'test'},{'test'},{'test'}]

exclusions = [{3,4},{4,5},{5,6},{6,7}]

for index,item in enumerate(a):
  if item in exclusions:
    a[index] = b.pop(0)

print(a)
>>>> [{1, 2}, {2, 3}, {'test'}, {'test'}, {'test'}, {'test'}]

b_iter = iter(b)
print([item if item < 0 or item > 4 else b_iter.next() for item in a])
>>>> TypeError: '<' not supported between instances of 'set' and 'int'

现在,按照他的逻辑,我不知道他会如何解决这个问题。

所以,正如我所说,在他的评论区中,请注意他的回答所暗示的内容。


1
你不需要在enumerate中使用[:],只需使用a。我认为这是更符合Python风格的答案。 - LinkBerest
enumerate是一个生成器,因此它只需要一个序列(任何序列或迭代器实际上)并且只是“生成”一个递增的索引以便在传递的序列中每个项目被yielded时使用(所以它不会制作任何副本,只是一个枚举对象,它正在移动)。如果您想了解更多信息,请查看PEP从添加时起。排除是可以的(实际上我考虑过,这取决于太多事情,无论我是否使用排除范围或try / except)。 - LinkBerest
从内存角度来看,这并不是非常高效的。想象一下,如果upper_boundlower_bound之间有很大的差异。你需要在内存中存储那么大的列表,并且每次for循环迭代时都要检查该列表中的每个项是否存在。 - Julian
@julian 我完全同意你的观点。但我认为人们应该在真正需要时关注性能和内存。我创建列表的想法是允许操作者使用其他类型(例如string)使用类似的逻辑。我将其设计成通用且易读,因为问题标题是通用的,这对未来的用户可能有益。 - scharette
@Julian,请阅读我的上面的评论或你的回答。我认为你会明白我想提供的答案。我还添加了一条注释。 - scharette
显示剩余5条评论

0

你可以像这样做。

list1=[0,1,6,4,2,8]
list2=[10,20,30,40]
j=0
ans=[0]*len(list1)
for i in range(len(list1)):
    if list1[i] <= 4:
        ans[list1.index(list1[i])]+=list2[j]
        if(j<len(list2)):
            j+=1
    else:
        ans[i]+=list1[i]

print(ans)

那应该可以工作。


我明白了,谢谢。此外,你的代码似乎有一些语法错误。这是因为使用了不同的Python版本吗? - Vinayak Suresh
我已经做了更改,你可以运行这段代码,在Python 3.6上它会正常工作。 - Raman Mishra
3
在编写代码时,请确保注重可读性。实际上,您应该思考一下,如果您是一个完全陌生的人看着您的代码,您是否能够理解它的目的? - scharette
1
其实你说得对,只是因为我有一段时间没有用Python了,所以我的代码有点乱。我会尽量让它更易读的,谢谢你的反馈。@scharette - Raman Mishra

0

你可以在列表b上使用一个计数器,并使用if语句仅替换小于4的数字:

a=[0,1,6,4,2,8]
b=[10,20,30,40]
n=0

for i in range(len(a)):
    if a[i] <= 4 and a[i] >= 0:
        a[i] = b[n]
        n += 1

你漏掉了一个 ) - scharette
如果 a 中有 -1,会怎样? - scharette
你可以将条件语句改为 a[i] > 0 并且 a[i] <= 4。 - Jay Heine
我知道,我的意思是OP要求0到4,这是你应该处理的。 - scharette
谢谢您的反馈,我对这个网站还不是很熟悉。 - Jay Heine

0

我认为这是一段更紧凑、更易读的代码。

a = [0, 1, 6, 4, 2, 8]
b = [10, 20, 30, 40]

temp = b
c = []
for item in a:
    if 0 <= item <= 4:
        c.append(temp.pop(0))
    else:
        c.append(item)

print(c)

0
你可以使用列表推导式和迭代器在两行代码中完成这个任务:
>>> b_iter = iter(b)
>>> [item if item < 0 or item > 4 else b_iter.next() for item in a]
[10, 20, 6, 30, 40, 8]

假设您的假设是a包含N个项目,其中0 < item < 4,并且b的长度也正好为N

此方法具有两个优点,相对于此处最高得票答案:

  1. 不需要exclusions列表,这只是浪费了内存。
  2. 这不会修改a列表,如果那不是您的意图,这可能会导致问题。

你应该注意,这仅适用于“int”类型,并且会以可读性为代价。 - scharette
  1. 我正在修改 a 列表,因为这是 OP 所要求的(我们剥离列表 a 中满足某个条件的元素,并将其简单地替换为列表 b 中的一个项目)。如果这个陈述是正确的,他从你的答案中得不到更多的东西。
- scharette
@scharette 你不仅错了,而且两种方式都错了... 1)我提出的解决方案不仅适用于 int,实际上它适用于可以通过 <> 进行比较的 floatintstr 或任何其他类型。 2)你提出的解决方案确实只适用于 int,因为 range 返回的是一个整数列表,请查看 range(start, stop[, step]) -> list of integers 的帮助文本。 - Julian
我使用了range(),因为OP的特定情况需要处理int,而它是创建整数列表的一种简洁方法。但在我的答案中,您可以像使用单词列表一样使用string类型,并且仍将有效。在您的情况下,您是正确的,即str支持<,但这绝不是任何人都想要的行为。我的意思是,目标是替换您可以在我的“排除”列表中指定的某些值。您的答案将比较两个字符串值,这在OP的上下文中完全奇怪。 - scharette
正如我之前所说,你的回答很高效,但是只适用于int和可能的float值,你应该明确声明。如果你决定不这样做,我就无法建议其他方法来提高你回答的质量。 - scharette
事实上,我已经编辑了我的答案,以便您更好地理解我的观点。希望这样能澄清问题! - scharette

-1
解决这个问题的主要思路是遍历列表a,检查每个值是否满足某些条件(在这种情况下,是否介于0和4之间),如果满足,则用列表b中相应的值替换它。您可以使用for循环和if语句来实现这一点。
for i in range(len(a) + 1):   # where a is your first list
    if a[i]==1: #checking a specific index of the list
        a[i] = 10
    elif a[i] == 2:
        a[i] = 20
    elif a[i] == 3:
        a[i] == 30
    elif a[i] == 4:
        a[i] == 40
    else:
        continue

希望这可以帮到你。


你说OP只想根据条件(在0和4之间)替换项目,但是你的代码没有检查这一点。此外,一组if/elif/else语句可以表明你需要一个字典或重新审视你的逻辑。我建议你看一下Jay的答案,因为它直接了当地解释了用单个if和计数变量来替换的逻辑。(注意:我没有给你的代码投反对票,但代码需要能够工作或者展示概念) - LinkBerest

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接