0

Is it possible to associate certain iterables in a loop with certain items from a list ? I have two lists to start with (totalpages and arguments) and I need to build up certain URL's.

totalpages = [300, 0]
arguments = ['argument1', 'argument2']
urllst = []

for i in totalpages:
  pages = list(range(0, x+100, 100))
  print(pages)
  for page, argument in zip(pages, arguments):
    urls = 'http://URL'+str(page)+argument
    urllst.append(urls)

urllst

I would like urllst to be like :

[
'http://URL0argument1',
'http://URL100argument1',
'http://URL200argument1',
'http://URL300argument1',
'http://URL0argument2'
]
hug
  • 247
  • 4
  • 14

3 Answers3

1

Let me write this answer to express my opinion on using index here.

You were very close to the solution, but zip'ped wrong lists finally. Here's what should work:

totalpages = [300, 0]
arguments = ['argument1', 'argument2']
urllst = []

for x, argument in zip(totalpages, arguments):
    for page in range(0, x+100, 100):
        url = f'http://URL{page}{argument}'
        urllst.append(url)

print(urllst)

This iterates over pairs (page_number, argument) made from two initial lists by taking items corresponding to the same indices. I switched to f-string to make string concatenation a bit prettier.

Here's a question about comparing index-based, enumerate-based and zip solutions for such kind of problems.

To ensure that input lists are of equal size, you can use zip(totalpages, arguments, strict=True) - this requires python version 3.10 or newer.

Finally, if you're appending in a loop, you're probably missing an optimisation opportunity: list comprehension would be faster, especially on long inputs.

totalpages = [300, 0]
arguments = ['argument1', 'argument2']
urllst = [
    f'http://URL{page}{argument}'
    for x, argument in zip(totalpages, arguments)
    for page in range(0, x+100, 100)
]

print(urllst)
STerliakov
  • 4,983
  • 3
  • 15
  • 37
1

With short zip (to aggregate elements from each of the iterables) + itertools.chain.from_iterable (to treat consecutive inner sequences as a single sequence) approach:

import itertools

urllst = list(itertools.chain.from_iterable(
    [f'http://URL{p}{arg}' for p in range(0, page + 100, 100)] 
    for page, arg in zip(totalpages, arguments)))

print(urllst)

The output:

['http://URL0argument1', 'http://URL100argument1', 'http://URL200argument1', 'http://URL300argument1', 'http://URL0argument2']
RomanPerekhrest
  • 88,541
  • 4
  • 65
  • 105
  • Wow, does `itertools.chain` have any advantages over plain listcomp with 2 `for`'s? Never thought of it's usage in such contexts. – STerliakov Dec 25 '22 at 20:28
-1

Printing pages after it has been instantiated as a list of numbers will not give you the proper output. It is simpler to just go through each number in a modified nested for-loop:

totalpages = [300, 0]
arguments = ['argument1', 'argument2']
urllst = []

for i in range(len(totalpages)):
  curr_arg = arguments[i]
  for x in range(0, totalpages[i]+100, 100):
    urls = 'http://URL'+str(x)+curr_arg
    urllst.append(urls)

print(urls)
okayatcp12
  • 308
  • 1
  • 9
  • 1
    I downvote, because OP already knows about `zip` and you provide un-pythonic index-based solution. (And this doesn't work at all, you try to access `arguments[300]` on the first step - it should be `for i in range(len(totalpages))` then, and it's **very** ugly) – STerliakov Dec 25 '22 at 20:05
  • @SUTerliakov what is the point of `zip` in this scenario though? `range(len(totalpages))` is a commonly used format. I think `zip` overcomplicates what is otherwise a very simple index-based solution. – okayatcp12 Dec 25 '22 at 20:06
  • 1
    Em, `for x, curr_arg in zip(totalpages, arguments)`, of course, to avoid indexing the lists?.. If you need `something[i]` and `something_else[i]` on every iteration, you cal always use `zip(something, something_else)` instead and throw the `i` index away. – STerliakov Dec 25 '22 at 20:09
  • Related discussion can be found [here](https://stackoverflow.com/questions/33955800/which-is-more-pythonic-in-a-for-loop-zip-or-enumerate). – STerliakov Dec 25 '22 at 20:10
  • Yes, but the size of `arguments` is not necessarily the same as `totalpages` because of the restriction that every argument's interval must be added as well. `zip` isn't a necessary addition to this solution and attempting to use it can , arguably, make the code look messier – okayatcp12 Dec 25 '22 at 20:12
  • If the size is not the same, then the problem is ill-defined. To prevent this from happening, you can use `zip(totalpages, arguments, strict=True)` on python 3.10 and newer. – STerliakov Dec 25 '22 at 20:13
  • But `strict` parameter asserts equal length when that is not the goal of OP's program. Saying the problem is "ill-defined" does not solve it. – okayatcp12 Dec 25 '22 at 20:15
  • 1
    Your code makes also an assumption (that is more 'hidden' than when using `zip`, so I would consider it a bad thing): that `arguments` will be at least as long as `total_pages`. Using indices doesn't help, it just makes things less clear. – Thierry Lathuille Dec 25 '22 at 20:21
  • ...so your solution just raises an IndexError, if lengths are different (well, if `arguments` is shorter than `totalpages`, to be strict). `zip(..., strict=True)` raises a `ValueError` in such case. What's the essential difference? – STerliakov Dec 25 '22 at 20:21