Which day I have been fighting with the algorithm, which I myself invented, but I can’t implement it, it sounds like this: There are number of illust , we know that the maximum number of lines of a two-dimensional post array can be no more than max_post , but no less than min_post . And the elements in these lines are not more than 7, moreover, the number of elements is always random from 2 to 7.

The goal is to fill the two-dimensional array with all the pictures, and the two-dimensional array was adjusted to the conditions that I said. Those. in the end, the elements in the lines, as it were, should stretch out (That's where I now have 7 elements, they could become two lines of 4 and 3 elements, then it would reach min_post ). I can't figure out how to do it ...

How can I optimize / rewrite / add it?

 illust = 108 # All pictures a = [] # array elemets = 0 #element in array illust_number = 1 #the current number of images post = 0 # line in array max_post = 40 min_post = 30 while elemets < illust: if illust_number < illust: while illust_number < illust: if illust_number < illust: elemets = random.randint(2, 7) if illust_number + elemets <= illust: a.append([]) for c in range(elemets): a[post].append(illust_number) illust_number += 1 else: elemets = random.randint(1, illust - illust_number) a.append([]) for c in range(elemets): a[post].append(illust_number) illust_number += 1 else: break post += 1 else: break 

Conclusion:

 [1, 2, 3, 4, 5] [6, 7, 8, 9, 10, 11] [12, 13] [14, 15, 16, 17] [18, 19, 20, 21, 22] [23, 24, 25] [26, 27, 28] [29, 30, 31, 32, 33, 34] [35, 36] [37, 38, 39, 40, 41, 42, 43] [44, 45, 46, 47, 48, 49, 50] [51, 52, 53, 54] [55, 56, 57, 58, 59, 60, 61] [62, 63, 64, 65, 66] [67, 68, 69, 70, 71, 72, 73] [74, 75] [76, 77] [78, 79, 80, 81, 82] [83, 84, 85, 86, 87, 88] [89, 90, 91] [92, 93, 94, 95, 96, 97, 98] [99, 100, 101, 102, 103, 104, 105] [106, 107] 
  • If you arrange 3 pictures in a row, without a random house, then the boundary conditions will be fulfilled 108 // 3 == 36 - Ilia w495 Nikitin
  • @ Iliaw495Nikitin, yes, only images can always be different, not only 108, but let's say: 40 or 200 - Marie Rose
  • @MarieRose write a function that will divide the list, and return the generator, then add the result to the main list. - Pavel Durmanov
  • @MarieRose Could you clarify the question a little, I don’t understand what you mean by lines? Is it count of arrays? Could you give an example of a conclusion that would suit you? Or the Conclusion that you provided you are satisfied with, is the question of code optimization? - Igor Lavrynenko

1 answer 1

To place npictures pictures in nrows_min..nrows_max rows and ncols_min..ncols_max columns:

 from itertools import zip_longest ncols = npictures // nrows_min if npictures < nrows_min * ncols_max else ncols_max print(*zip_longest(*[iter(range(1, npictures + 1))]*ncols), sep='\n') 

Where:

 npictures = 108 # количество картинок nrows_max = 40 # максимальное количество строк nrows_min = 20 # минимальное количество строк ncols_max = 7 # максимальное количество столбцов ncols_min = 2 # минимальное количество столбцов assert nrows_min * ncols_min <= npictures <= nrows_max * ncols_max assert nrows_min < nrows_max 

Example:

 (1, 2, 3, 4, 5) (6, 7, 8, 9, 10) (11, 12, 13, 14, 15) (16, 17, 18, 19, 20) (21, 22, 23, 24, 25) (26, 27, 28, 29, 30) (31, 32, 33, 34, 35) (36, 37, 38, 39, 40) (41, 42, 43, 44, 45) (46, 47, 48, 49, 50) (51, 52, 53, 54, 55) (56, 57, 58, 59, 60) (61, 62, 63, 64, 65) (66, 67, 68, 69, 70) (71, 72, 73, 74, 75) (76, 77, 78, 79, 80) (81, 82, 83, 84, 85) (86, 87, 88, 89, 90) (91, 92, 93, 94, 95) (96, 97, 98, 99, 100) (101, 102, 103, 104, 105) (106, 107, 108, None, None) 

To fulfill the requirement of ncols_min , it is possible to assemble one element from the previous lines (perhaps more than once, if there are few lines) until at least ncols_min elements are typed.

In order for this algorithm, with a valid input, to not make the previous lines too narrow, you can choose the largest possible ncols :

 from math import ceil ncols = min(ceil(npictures / nrows_min), ncols_max) 

So that the lines can be edited, you can submit them as lists:

 rows = list(map(list, zip_longest(*[iter(range(1, npictures + 1))]*ncols))) while rows[-1][-1] is None: # remove trailing None values rows[-1].pop() 

In this case, the number of lines may be less than nrows_min , so you need to add the missing lines:

 rows += [[] for _ in range(nrows_min - len(rows))] # len(rows) >= nrows_min 

Then the above algorithm ( in italics ), which adds elements to short lines (so that each line is added to ncols_min ):

 for i in range(len(rows)-1, -1, -1): while len(rows[i]) < ncols_min: for j in range(i-1, -1, -1): if len(rows[j]) > ncols_min: rows[i].append(rows[j].pop()) if len(rows[i]) == ncols_min: break elif j == 0: raise ValueError("impossible constraints") assert nrows_min <= len(rows) <= nrows_max assert all(ncols_min <= len(row) <= ncols_max for row in rows) 

In this case, the result is:

 [[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12], [13, 14, 15, 16, 17, 18], [19, 20, 21, 22, 23, 24], [25, 26, 27, 28, 29, 30], [31, 32, 33, 34, 35, 36], [37, 38, 39, 40, 41, 42], [43, 44, 45, 46, 47, 48], [49, 50, 51, 52, 53, 54], [55, 56, 57, 58, 59, 60], [61, 62, 63, 64, 65, 66], [67, 68, 69, 70, 71, 72], [73, 74, 75, 76, 77, 78], [79, 80, 81, 82, 83, 84], [85, 86, 87, 88, 89, 90], [91, 92, 93, 94, 95, 96], [97, 98, 99, 100], [103, 104, 105, 106], [107, 101], [108, 102]] 

How zip(*[iterator]*n) idiom works, see the links in the answer .