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
for chunk in map(''.join, zip(*[iter(strng)]*sz))
Inside out:
iter(strng) returns an iterator that each time is accessed using next or in an loop consumes an element (a character) of strng and returns said element.
[iter(strng)] is a list, its unique element is the iterator
[iter(strng)]*sz is the concatenation of sz copies of the list, [iter(strng), ..., iter(strng)] containing sz 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 to zip(iter(strng), ..., iter(strng)).
At each iteration zip takes the first element of each of its arguments and place them in a tuple, but because the various references to iter all refer to the same, original instance of iter(strng) the first tuple returned by zip contains the first sz characters of strng, the second contains the sz+1 to 2*sz characters etc etc.
Finally, each of this tuples is the argument of ''.join(), so we have a series of strings each long sz characters, spanning the original strng.
That's it.
Related
i want my code to find the position of capital letters and add them to an array. After testing, i get the error: TypeError: list.append() takes exactly one argument (2 given)
also when testing with a input with a singular capital letter it works fine, however when they are multiple capital letters, the array will only contain the last position.
for i in range(0,length):
letter = camel_case[i]
for k in range(0,25):
check = capitals[k]
if check == letter:
position = i
print(f"{position}")
global caps
caps = []
caps.append(capital_quantity,i)
capital_quantity = capital_quantity + 1
else:
pass
The error is self-explanatory. The append function only takes a single parameter but two were passed.
Replace the following line of code:
caps.append(capital_quantity,i)
with this:
caps.append(capital_quantity)
For lists, you can only append one item at a time. If you would like to keep capital_quantity and i together you could append them to your list as a secondary list i.e.
caps.append([capital_quantity,i])
Its worth noting, if for whatever reason you want to add both values to your list in a flat structure rather than a nested list you could use the.extend() method. This is a good tutorial to understand the behavior.
Seems like you got list.append and list.insert mixed up.
list.append takes in one argument to add to the end of the list, whereas list.insert takes both a positional argument and the item to insert in that position of the list.
Additionally, there appears to be other bugs/fixes in your code.
range(0,25) should be range(0,26) since the last item in the range will be one less than the end argument (numbers 0-24 instead of 0-25)
caps=[] sets the list caps to an empty list every time it's called. I don't think that's what you want.
You don't need the else:pass
You don't need the capital_quantity. Just use list.append. If you need to count how many capitals are in the list, just do len(caps)
Here's how I'd implement this problem the most straightforward way:
caps=[]
for i,c in enumerate(camel_case):
if c.isupper():
caps.append(i)
We check if each character c in the string camel_case is uppercase, and if it is, we append its index i to the list.
You can save two or more data in a list with curly braces like this.
caps.append({capital_quantity,i})
I'm looking to write a piece of code in Javascript or Python that generates a wordlist file out of a pre-defined combination of characters.
E.g.
input = abc
output =
ABC
abc
Abc
aBc
abC
AbC
ABc
aBC
I have very basic knowledge of either so all help is appreciated.
Thank you
I'll assume that you're able to import Python packages. Therefore, take a look at itertools.product:
This tool computes the cartesian product of input iterables.
For example, product(A, B) returns the same as ((x,y) for x in A for y in B).
It looks quite like what you're looking for, right? That's every possible combination from two different lists.
Since you're new to Python, I'll assume you don't know what a map is. Nothing too hard to understand:
Returns a list of the results after applying the given function to each item of a given iterable (list, tuple etc.)
That's easy! So the first parameter is the function you want to apply and the second one is your iterable.
The function I applied in the map is as follows:
''.join
This way you set '' as your separator (basically no separator at all) and put together every character with .join.
Why would you want to put together the characters? Well, you'll have a list (a lot of them in fact) and you want a string, so you better put those chars together in each list.
Now here comes the hard part, the iterable inside the map:
itertools.product(*((char.upper(), char.lower()) for char in string)
First of all notice that * is the so-called splat operator in this situation. It splits the sequence into separate arguments for the function call.
Now that you know that, let's dive into the code.
Your (A, B) for itertools.product(A, B) are now (char.upper(), char.lower()). That's both versions of char, upper and lowercase. And what's char? It's an auxiliar variable that will take the value of each and every character in the given string, one at a time.
Therefore for input 'abc' char will take values a, b and c while in the loop, but since you're asking for every possible combination of uppercase and lowercase char you'll get exactly what you asked for.
I hope I made everything clear enough. :)
Let me know if you need any further clarification in the comments. Here's a working function based on my previous explanation:
import itertools
def func():
string = input("Introduce some characters: ")
output = map(''.join, itertools.product(*((char.upper(), char.lower()) for char in string)))
print(list(output))
As an additional note, if you printed output you wouldn't get your desired output, you have to turn the map type into a list for it to be printable.
A simple approach using generators, and no library code. It returns a generator (iterator-like object), but can be converted to a list easily.
def lU(s):
if not s:
yield ''
else:
for sfx in lU(s[1:]):
yield s[0].upper() + sfx
yield s[0].lower() + sfx
print list(lU("abc"))
Note that all the sub-lists of suffixes are not fully expanded, but the number of generator objects (each a constant size) that get generated is proportional to the length of the string.
I have a list of strings which looks like this:
['(num1, num2):1', '(num3, num4):1', '(num5, num6):1', '(num7, num8):1']
What I try to achieve is to reduce this list and combine every two elements and I want to do this until there is only one big string element left.
So the intermediate list would look like this:
['((num1, num2):1,(num3, num4):1)', '((num5, num6):1,(num7, num8):1)']
The complicated thing is (as you can see in the intermediate list), that two strings need to be wrapped in paranthesis. So for the above mentioned starting point the final result should look like this:
(((num_1,num_2):1,(num_3,num_4):1),((num_5,num_6):1,(num_7,num_8):1))
Of course this should work in a generic way also for 8, 16 or more string elements in the starting list. Or to be more precise it should work for an=2(n+1).
Just to be very specific how the result should look with 8 elements:
'((((num_1,num_2):1,(num_3,num_4):1),((num_5,num_6):1,(num_7,num_8):1)),(((num_9,num_10):1,(num_11,num_12):1),((num_13,num_14):1,(num_15,num_16):1)))'
I already solved the problem using nested for loops but I thought there should be a more functional or short-cut solution.
I also found this solution on stackoverflow:
import itertools as it
l = [map( ",".join ,list(it.combinations(my_list, l))) for l in range(1,len(my_list)+1)]
Although, the join isn't bad, I still need the paranthesis. I tried to use:
"{},{}".format
instead of .join but this seems to be to easy to work :).
I also thought to use reduce but obviously this is not the right function. Maybe one can implement an own reduce function or so?
I hope some advanced pythonics can help me.
Sounds like a job for the zip clustering idiom: zip(*[iter(x)]*n) where you want to break iterable x into size n chunks. This will discard "leftover" elements that don't make up a full chunk. For x=[1, 2, 3], n=2 this would yield (1, 2)
def reducer(l):
while len(l) > 1:
l = ['({},{})'.format(x, y) for x, y in zip(*[iter(l)]*2)]
return l
reducer(['(num1, num2):1', '(num3, num4):1', '(num5, num6):1', '(num7, num8):1'])
# ['(((num1, num2):1,(num3, num4):1),((num5, num6):1,(num7, num8):1))']
This is an explanation of what is happening in zip(*[iter(l)]*2)
[iter(l)*2] This creates an list of length 2 with two times the same iterable element or to be more precise with two references to the same iter-object.
zip(*...) does the extracting. It pulls:
Loop
the first element from the first reference of the iter-object
the second element from the second reference of the iter-object
Loop
the third element from the first reference of the iter-object
the fourth element from the second reference of the iter object
Loop
the fifth element from the first reference of the iter-object
the sixth element from the second reference of the iter-object
and so on...
Therefore we have the extracted elements available in the for-loop and can use them as x and y for further processing.
This is really handy.
I also want to point to this thread since it helped me to understand the concept.
I'm working through a tutorial which includes this code:
for position, target in population_gen(population):
pos = float(position)
all_inputs.append([random.random(), pos * factor])
all_targets.append([target])
I don't fully understand how the for loop works. In particular: what is the loop iterating through exactly? I'm only familiar with simple examples like for i in mylist:. How can there be a function call on the right-hand side of in, and two things separated by a comma on the left-hand side?
The function population_gen is returning a list of tuples, which are unpacked automatically into variable names using this syntax.
So basically, you're getting something like the following as return value from the function:
[("pos1", "target1"), ("pos2", "target2"), ]
Given this example, in the the for loop's first iteration, the variables "position" and "target" will have the values:
position = "pos1"
target = "target1"
In second iteration:
position = "pos2"
target = "target2"
Tuple unpacking.
for a, b in [(1, 2), (3, 4)]:
print a
print b
print 'next!'
And the function is just a function.
The function either returns a sequence or serves as something called a "generator:" it spits out successive elements in a sequence for the caller to iterate through. This question concerning the yield keyword has some thorough discussion of how these work.
As for the comma, since the function (apparently) returns a two-tuple, the comma-separated list of names is a convenient way to name individual elements of the tuple without having to unpack them yourself.
It's called tuple unpacking. The population_gen (generator) function yields tuples containing exactly two elements. In python, you can assign several variables to tuples like this
a, b = (1, 2)
So in this for loop, you directly put the two tuple values from the current iteration item into your two variables position and target.
I've started teaching myself Python, and as an exercise I've set myself the task of generating lookup tables I need for another project.
I need to generate a list of 256 elements in which each element is the value of math.sin(2*i*pi/256). The problem is, I don't know how to generate a list initialized to "dummy" values that I can then use a for loop to step through and assign the values of the sin function.
Using list() seems to create an "empty" list, but with no elements so I get a "list assignment index out of range" error in the loop. Is there a way to this other than explicitly creating a list declaration containing 256 elements all with "0" as a value?
Two answers have already shown you how to build your list at a single stroke, using the "list comprehension" (AKA "listcomp") construct.
To answer your specific question, though,
mylist = [None] * 256
is the simplest way to make a list with 256 items, all None, in case you want to fill it in later.
If you start with an empty list, call its .append(...) method to add each item at the end. A loop doing nothing but append on an initially-empty list is what normally gets replaced with a more concise listcomp.
Of course, for the task you actually state,
mylist = [math.sin(2 * math.pi/256)] * 256
would be by far the best approach -- no sense computing a sin 256 times when the argument's always the same (daringly assuming that what you say is what you mean;-).
my_list = [math.sin(2 * math.pi/256) for i in xrange(256)]
You can also try:
l = []
for i in range(256):
l.append(math.sin(2*math.pi/256))
This is an iterative for loop that keeps adding the same value to the end of the list 256 times
I need to generate a list of 256
elements in which each element is the
value of math.sin(2*math.pi/256)
To answer your question literally:
my_list=[math.sin(2*math.pi/256)]*256
Thanks for the help, everyone. I did make a mistake in the specification I posted for the question, in that the value of each element in the list needs to be the sin of the angle incremented by 2*pi/256 each time. The code that works for me in that case is:
li = [math.sin((2*math.pi/256)*i) for i in xrange(0,256)]