简体   繁体   中英

Is there a cleaner way than using for loops

I would like to know if there are any other ways to loop and manipulate data located in separate arrays.

import numpy as np

a = np.arange(2)
b = np.arange(5)
c = np.arange(5)

l1 = []
for x in a:
    l2 = []
    for y in b: 
        l3 = []
        y = x + 1  
        for z in c:
            z = x + y
            t = (x,y,z)
            l3.append(t)
        l2.append(l3)
    l1.append(l2) 
print l1

This code does exactly what you are doing.

def method(lst, range1, range2):
    for i in lst:
        yield [[(i, i+1, 1+(i*2))]*range2]*range1

Can even be turned into a generator expression:

def gen_method(lst, r1, r2):
    return ([[(i, i+1, 1+(i*2))]*r2]*r1 for i in lst)

Test it yourself if you like.


My tests:

a = range(2)
b = range(5)
c = range(5)

def your_method(a, b, c):
    l1 = []
    for x in a:
        l2 = []
        for y in b: 
            l3 = []
            y = x + 1  
            for z in c:
                z = x + y
                t = (x,y,z)
                l3.append(t)
            l2.append(l3)
        l1.append(l2)
    return l1

def my_method(lst, range1, range2):
    for i in lst:
        yield [[(i, i+1, 1+(i*2))]*range2]*range1

yours = your_method(a, b, c)
mine = list(my_method(a, len(b), len(c)))

print yours
print '==='
print mine
print '==='
print yours == mine

>>> 
[[[(0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1)], [(0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1)], [(0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1)], [(0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1)], [(0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1)]], [[(1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3)], [(1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3)], [(1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3)], [(1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3)], [(1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3)]]]
===
[[[(0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1)], [(0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1)], [(0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1)], [(0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1)], [(0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1)]], [[(1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3)], [(1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3)], [(1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3)], [(1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3)], [(1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3)]]]
===
True

Well, you can compress the code using list comprehensions:

[[[(x,x+1,x*2 +1)]*len(c)]*len(b) for x in a]

What this does is loop for all x in a, and create a list of elements, where each element is a list generated for all y in b, where each element of that list is (x,x+1,2*x+1) for all z in c.

An alternative approach is to use itertools , convert the resulting list to numpy array and reshape it

import numpy as np
import itertools as it

a = np.arange(2)
b = np.arange(5)
c = np.arange(5)

l1 = np.array([(i, i+1, i*2+1) for i, rb, rb in it.product(a, b, c)])
l1 = l1.reshape(len(a), len(b), len(c), len(d[0]))

It might be that this gets more memory consuming than all the other approaches as the size increases, but it 's only two lines and creates unique elements for each triplet instead of just creating multiple pointers to the same object.

Edit

An other way, that also allows to keep the triplet (i, i+1, i*1+1) as a list is:

l1 = np.empty([len(a), len(b), len(c)], dtype=object)
for i, rb, rb in it.product(a, b, c):
    l1[i,ra, rb] = (i, i+1, i*2+1)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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