# Transpose. # # Note what the main diagonal same in l and lT l = [ [1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12] ] lT = [ [1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12] ] lTT = [ [1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12] ] # lTT = l # # It is as the reflection elements along its main diagonal [1, 6, 11] # In mean, rows rearrange in columns and columns rearrange in rows. from time import time # Transpose function version 1.0. It's don't necessary def transpose1_0(a: list) -> list: """Transpose matrix version 1.0""" r = [] c = 0 #counter max_j = len(a[c]) # for begin is len(a[0]) j = 0 while j < max_j: i = 0 sr = [] while i < len(a): if j < len(a[i]): sr.append(a[i][j]) else: sr.append(0) # For example if meet rows with different size i += 1 r.append(sr) j += 1 c += 1 max_j = max(max_j, len(a[c%len(a)])) return r # Transpose function version 1.1. def transpose1_1(a: list) -> list: """Transpose matrix version 1.1""" r = [] for j in range(len(max(a))): sr = [] for i in range(len(a)): if j < len(a[i]): sr.append(a[i][j]) else: sr.append(0) r.append(sr) return r # Transpose function version 1.2. def transpose1_2(a: list) -> list: """Transpose matrix version 1.2""" r = [] max_j = len(max(a)) row_count = len(a) for j in range(max_j): sr = [] for i in range(row_count): if j < len(a[i]): sr.append(a[i][j]) else: sr.append(0) r.append(sr) return r # Transpose function version 1.3 ********************************************** def transpose1_3(a: list) -> list: """Transpose matrix version 1.3""" return [ [row[j] if j < len(row) else 0 for row in a] for j in range(len(max(a)))] # Transpose function version 1.3.1 ******************************************** def transpose1_3_1(a: list) -> list: """Transpose matrix version 1.3.1""" max_j = len(max(a)) return [ [row[j] if j < len(row) else 0 for row in a] for j in range(max_j)] # ***************************************************************************** # Transpose function version 1.4 def transpose1_4(a: list) -> list: """Transpose matrix version 1.4""" r = [] max_j = len(max(a)) row_count = len(a) for j in range(max_j): sr = [] for i in range(row_count): sr.append(a[i][j] if j < len(a[i]) else 0) r.append(sr) return r # Transpose generator ********************************************************* def transpose_generator(a: list) -> list: """Transpose generator""" for j in range(len(max(a))): yield [row[j] if j < len(row) else 0 for row in a] #****************************************************************************** def test(): count = 1000 T1_0 = 0 T1_1 = 0 T1_2 = 0 T1_3 = 0 T1_4 = 0 T1_5 = 0 T1_6 = 0 T1_7 = 0 for i in range(count): t10 = time() transpose1_0(lT) t20 = time() T1_0 += t20 - t10 t11 = time() transpose1_1(lT) t21 = time() T1_1 += t21 - t11 t12 = time() transpose1_2(lT) t22 = time() T1_2 += t22 - t12 t13 = time() transpose1_3(lT) t23 = time() T1_3 += t23 - t13 t14 = time() transpose1_3_1(lT) t24 = time() T1_4 += t24 - t14 t15 = time() transpose1_4(lT) t25 = time() T1_5 += t25 - t15 t16 = time() list(transpose_generator(lT)) t26 = time() T1_6 += t26 - t16 t17 = time() list(zip(*lT)) t27 = time() T1_7 += t27 - t17 print(0, "transpose1_0(lT)", "Time = ", T1_0/count, " ", transpose1_0(lT)) print(1, "transpose1_1(lT)", "Time = ", T1_1/count, " ", transpose1_1(lT)) # Faster than first. print(2, "transpose1_2(lT)", "Time = ", T1_2/count, " ", transpose1_2(lT)) # Naturally faster than the second. # It's show, what not necessary to calculate max_j and row_count at each iteration. print(3, "transpose1_3(lT)", "Time = ", T1_3/count, " ", transpose1_3(lT)) # Faster than previous. print(4, "transpose1_3_1(lT)", "Time = ", T1_4/count, " ", transpose1_3_1(lT)) # Not a big difference. # Conclusion: it is better to carry out the calculation of immutable data for a cycle, # then they will be calculated once, and not at each iteration. print(5, "transpose1_4(lT)", "Time = ", T1_5/count, " ", transpose1_4(lT)) # transpose1_4 to compare with transpose1_2, because here if expression is different. print(6, "transpose_generator(lT)", "Time = ", T1_6/count, " ", list(transpose_generator(lT))) # The generator works good, slightly slower than transpose1_3, which is the fastest so far. # However, it has a different purpose, so it makes sense to implement two functions at once. print(7, "zip(*lT)", "Time = ", T1_7/count, " ", list(zip(*lT))) # Slower than the first function # It is much slower than other functions. In addition, it will not pass the test: # If the nested lists are of different lengths, it will produce a completely incorrect (for transporting) result. # If the first nested list is empty, it will return an empty list as the result. # In other functions, empty values ​​are replaced with 0. # https://en.wikipedia.org/wiki/Transpose if __name__ == "__main__": test() """More effectively for tutorial will be transpose function version 1.3.1 because she faster, don't executing made work in loop and use if-else statement."""