Home > Net >  Convert for loop to List Comprehension Python
Convert for loop to List Comprehension Python

Time:11-05

The problem is for all the numbers (1 - 20) the highest single digit (1 - 9) of any of the numbers is divisible by.

I have a for loop as given below:

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:

[[], [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.

CodePudding user response:

The problem is for all the numbers (1 - 20) the highest single digit (1 - 9) of any of the numbers is divisible by.

I'd implement it in another way using 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. I used list.insert() here to make it produce result in same order as your solution.

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 of reversed() (as i suggested in another comment) or reverse it using slicing to make it return list in proper order:

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

CodePudding user response:

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:

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)
]

CodePudding user response:

Why do you need the first empty list? The solution proposed by @Olvin makes clever use of 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).
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. 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...

  • Related