I'm studying someone else's solution on Codewars and am a little puzzled about something. Here is a link to the original question: Reverse or Rotate?. Credit goes to the original author, falsetru.
Here's the solution:
def revrot(strng, sz):
return ''.join(
chunk[1:] + chunk[:1] if sum(int(d)**3 for d in chunk) % 2 else chunk[::-1]
for chunk in map(''.join, zip(*[iter(strng)]*sz))
)
I think I understand most of it. Except for this part:
zip(*[iter(strng)]*sz)
I think that the * used in this way signifies a non-keyworded variable-length argument list - meaning that there could be any number of pieces of the original string (strng
), which are of length sz
, for example, 6. The zip()
function is receiving some variable number of iterables, which is what it requires, per the documentation. (Right?)
So then, map(''.join, zip(*[iter(strng)]*sz)
first returns an iterator for the string strng
. It returns this inside of a list. It seems like that list is then multiplied by sz
(why?). It returns a variable number of results to zip (thus the *
). zip()
returns a tuple (I guess?), which is then passed through the join
function via map
.
Questions:
- Is that even close to being right?
- Why must iter(strng) be placed inside a list
[]
? - Why can you join the result of
zip
? I tried joining('m',)
as a test and got'm'
. Confused as to why that works as well. - Can someone explain more about the *? I'm confused as to when I should use it...
Thanks. I'm still a late beginner in Python so I appreciate the help! (Even for just a piece of my question!)
To understand what is happening, we want to analyze the statement
Inside out:
iter(strng)
returns an iterator that each time is accessed usingnext
or in an loop consumes an element (a character) ofstrng
and returns said element.[iter(strng)]
is a list, its unique element is the iterator[iter(strng)]*sz
is the concatenation ofsz
copies of the list,[iter(strng), ..., iter(strng)]
containingsz
times the same iterator object, I mean literally the same iterator object.*[iter(strng)]*sz
is equivalent to*[iter(strng), ..., iter(strng)]
and, when used in a function argument list, unpacks its contents: the function sees its list of arguments as(iter(strng), ..., iter(strng))
.zip(*[iter(strng)]*sz)
is hence equivalent tozip(iter(strng), ..., iter(strng))
.zip
takes the first element of each of its arguments and place them in a tuple, but because the various references toiter
all refer to the same, original instance ofiter(strng)
the first tuple returned byzip
contains the firstsz
characters ofstrng
, the second contains thesz+1
to2*sz
characters etc etc.''.join()
, so we have a series of strings each longsz
characters, spanning the originalstrng
.That's it.