简体   繁体   English

将 for 循环转换为 List Comprehension Python

[英]Convert for loop to List Comprehension Python

The problem is for all the numbers (1 - 20) the highest single digit (1 - 9) of any of the numbers is divisible by.问题是对于所有数字 (1 - 20),任何数字中最高的一位数 (1 - 9) 都可以被整除。

I have a for loop as given below:我有一个 for 循环,如下所示:

values = [[] for value in range(1, 11)]

for num in range(1, 21):
    highest = 0
    for div in range(1, 10):
        if(num % div == 0 and div > highest):
            highest = div
    
    values[highest].append(num)

The following for loop output:以下 for 循环输出:

[[], [1, 11, 13, 17, 19], [2], [3], [4], [5, 10, 15, 20], [6, 12], [7, 14], [8, 16], [9, 18]]

The empty list [] that in the output can be ignored.输出中的空列表 [] 可以忽略。 For example:例如:

[[1, 11, 13, 17, 19], [2], [3], [4], [5, 10, 15, 20], [6, 12], [7, 14], [8, 16], [9, 18]]

I want to convert the following for loop to list comprehension, can anyone please help me.我想将以下 for 循环转换为列表理解,任何人都可以帮助我。

The problem is for all the numbers (1 - 20) the highest single digit (1 - 9) of any of the numbers is divisible by.问题是对于所有数字 (1 - 20),任何数字中最高的一位数 (1 - 9) 都可以被整除。

I'd implement it in another way using list.pop() :我会使用list.pop()以另一种方式实现它:

nums = list(range(1, 21))
values = []
for d in range(9, 0, -1):
    temp = []
    for i in range(len(nums) - 1, -1, -1):  # iterating in reverse order
        if not nums[i] % d:  # nums[i] % d == 0
            temp.insert(0, nums.pop(i))
    values.insert(0, temp)
print(values)

Basically, we initialize list of numbers from 1 to 20 and pop value which divisible by digit.基本上,我们初始化从120的数字列表和可被数字整除的弹出值。 I used list.insert() here to make it produce result in same order as your solution.我在这里使用了list.insert()使其以与您的解决方案相同的顺序产生结果。

In comment I posted code which will produce list in reversed order, here is it:评论中,我发布了将以相反顺序生成列表的代码,如下所示:

nums = list(range(1, 21))
values = [[nums.pop(i) for i in range(len(nums) - 1, -1, -1) if not nums[i] % d] for d in range(9, 0, -1)]

You can add two calls ofreversed() (as i suggested in another comment ) or reverse it using slicing to make it return list in proper order:您可以添加两个reversed()调用(正如我在另一条评论中建议的那样)或使用切片反转它以使其以正确的顺序返回列表:

nums = list(range(1, 21))
values = [[nums.pop(i) for i in range(len(nums) - 1, -1, -1) if not nums[i] % d][::-1] for d in range(9, 0, -1)][::-1]

Upd.更新。 I've decided to add some tests result which should help to see why list comprehension doesn't make it any better.我决定添加一些测试结果,这应该有助于了解为什么列表理解不会让它变得更好。 If you want to reproduce tests, code is here .如果你想重现测试,代码在这里

Tests results (lower is better) :测试结果(越低越好)

Temple Version: 0.49361748499999997
Tranbi: 1.794325605
JonSG: 5.4978652320000005
JonSG(+ Olvin): 4.834248347000001
Olvin Roght (v1): 0.34827960000000147
Olvin Roght (v2): 0.4133600079999997
Kelly Bundy: 0.19429717999999951
Temple Version(+ Kelly): 0.20479166999999876

Here is a slightly different take on the comprehension.这是对理解略有不同的看法。

values = [
    [
        num for num
        in range(1, 21)
        if index == max([
            i for i
            in range(1, 10)
            if not num%i
        ])
    ] for index, _
    in enumerate(range(1, 11))
]
print(values)

This will give you:这会给你:

[[], [1, 11, 13, 17, 19], [2], [3], [4], [5, 10, 15, 20], [6, 12], [7, 14], [8, 16], [9, 18]]

It can be simplified a bit but I was attempting to match what you had done as closely as I could.它可以简化一点,但我试图尽可能地匹配你所做的。

Here is a straightforward simplification and improvement as highlighted by @olvin-roght:这是@olvin-roght 强调的一个简单的简化和改进:

values = [
    [
        num for num in range(1, 21)
        if index == next(i for i in range(9, 0, -1) if not num%i)
    ] for index in range(10)
]

Why do you need the first empty list?为什么需要第一个空列表? The solution proposed by @Olvin makes clever use of pop . @Olvin 提出的解决方案巧妙地利用了pop You'll have to reverse it to get what you want though.你必须扭转它才能得到你想要的东西。

Here a solution that might be easier to understand and gives you the result you expect:这是一个可能更容易理解并为您提供预期结果的解决方案:

print([ [num for num in range(1,21) if num % div == 0 and all(num % x != 0 for x in range(div + 1, 10)) ] for div in range(1,10)])

Output:输出:

[[1, 11, 13, 17, 19], [2], [3], [4], [5, 10, 15, 20], [6, 12], [7, 14], [8, 16], [9, 18]]

The use of all will generate more computing time (so will reverse in the other solution).使用all将产生更多的计算时间(因此在其他解决方案中会相反)。
It's fun to create comprehension if you want to train but loops are fine as well.如果你想训练,创造理解很有趣,但循环也很好。 And here much easier to read!在这里更容易阅读!

EDIT编辑

Since so many people commented on the question and my answer I started to look closer to the problem and timed all solutions.由于有这么多人对这个问题和我的回答发表评论,我开始仔细研究问题并为所有解决方案计时。 It turns out @Olvin's solution is the fastest and matches the speed of OP's loop.事实证明@Olvin 的解决方案是最快的,并且与 OP 的循环速度相匹配。 Followed by my solution (approx. 3x slower on my machine) and @JonSG's solution (9x slower) turns out reversing the lists is much better optimized than I thought...其次是我的解决方案(在我的机器上慢了大约 3 倍)和@JonSG 的解决方案(慢了 9 倍)结果反转列表比我想象的要优化得多......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM