In idiomatic C fashion, one can implement quicksort in a simple way with two arguments:
void quicksort(int inputArray[], int numelems);
We can safely use two arguments for later subdivisions (i.e. the partitions, as they're commonly called) via pointer arithmetic:
//later on in our quicksort routine...
quicksort(inputArray+last+1, numelems-last-1);
In fact, I even asked about this before on SO because I was untrained in pointer arithmetic at the time: see Passing an array to a function with an odd format - “v+last+1”
Basically, Is it possible to replicate the same behavior in python and if so, how? I have noticed that lists can be subdivided with the colon inside of square brackets (the slicing operator), but the slice operator does not pass the list from that point on; that is to say that the 1st element (0th index) is still the same in both cases.
As you're aware, Python's slice syntax makes a copy, so in order to manipulate a subsection of a list (not "array", in Python) in place, you need to pass around both the list and the start-index and size (or end-index) of the portion under discussion, much as you could in C. The signature of the recursive function would be something like:
def quicksort( inputList, numElems, startIndex = 0 ):
And the recursive call would be something like:
quicksort( inputList, numElems-last-1, last+1 )
Throughout the function you'd add startIndex to whatever list accesses you would make.
I suppose if you want to do something like that you could do the following:
# list we want to mutate
sort_list = [1,2,3,4,5,6,7,8,9,0]
#wrapper just so everything looks pretty, process could go here if we wanted
def wrapper(a, numlems):
cut = len(a) - numlems
# overwrites a part of the list with another one
a[cut:] = process(a[cut:])
# processing of the slice
def process(a):
# just to show it works
a[1] = 15
return a
wrapper(sort_list, 2)
print(sort_list)
wrapper(sort_list, 4)
print(sort_list)
wrapper(sort_list, 6)
print(sort_list)
This is probably considered pretty evil in python and I wouldn't really recommend it, but it does emulate the functionality you wanted.
For python you only really need:
def quicksort(inputList, startIndex):
Then creating and concatenating slices would work fine without the need for pointer like functionality.
Related
I have the following problem and two very important questions.
Write a class called Wordplay. It should have a field that holds a list of words. The user
of the class should pass the list of words they want to use to the class. There should be the
following methods:
words_with_length(length) — returns a list of all the words of length length
starts_with(s) — returns a list of all the words that start with s
ends_with(s) — returns a list of all the words that end with s
palindromes() — returns a list of all the palindromes in the list
First problem. After compiling my program the methods starts with and ends with return the same word.
Next problem. In this case i have created a list of three names. But what if i wanted to ask for a list size and iterate over it while asking to input a word. How can i implement that idea?
class Wordplay:
def __init__(self):
self.words_list=[]
def words_with_lenght(self,lenght):
for i in range(0,len(self.words_list)-1):
if len(self.words_list[i])==lenght:
return self.words_list[i]
def starts_with_s(self,s):
for i in range(0,len(self.words_list)-1):
if s.startswith('s')==True:
return self.words_list[i]
def ends_with_s(self,s):
for i in range(0,len(self.words_list)-1):
if s.endswith('s')==True:
return self.words_list[i]
def palindromes(self):
for i in range(0,len(self.words_list)-1):
normal_word=self.words_list[i]
reversed_word=normal_word[::-1]
if reversed_word==normal_word:
return reversed_word
verification=Wordplay()
verification.words_list=['sandro','abba','luis']
lenght=int(input('Digit size you want to compare\n'))
s='s'
print(verification.words_with_lenght(lenght))
print(verification.starts_with_s(s))
print(verification.ends_with_s(s))
print(verification.palindromes())
If i input for example size 4 i expect the result to be:
abba,luis ; sandro ; luis ; abba and not-
abba; sandro ; sandro ; abba
In the line if s.startswith('s')==True:, you've passed the string "s" into the function resulting in
if 's'.startswith('s')==True:
# ^^^
return self.words_list[i]
This conditional is always true. You probably don't need a parameter here at all since the assignment asks you to hard code "s". You can use:
if self.words_list[i].startswith('s'):
return self.words_list[i]
Notice the above example uses a return as soon as a match is found. This is a problem. The loops in this program break early, returning from the function as soon as a single match is located. You may have intended to append each successful match to a list and return the resulting list or use the yield keyword to return a generator (but the caller would need to use list() if they want a persistent list from the generator). Using a list to build a result would look like:
result = []
for i in range(len(self.words_list)):
if self.words_list[i].startswith('s'):
result.append(self.words_list[i])
return result
Another issue: the loops in this program don't iterate all the way through their respective lists. The range() function is inclusive of the start and exclusive of the end, so you likely intended range(len(self.words_list)) instead of range(0, len(self.words_list) - 1).
Beyond that, there are a number of design and style points I'd like to suggest:
Use horizontal space between operators and use vertical whitespace around blocks.
foo=bar.corge(a,b,c)
if foo==baz:
return quux
is clearer as
foo = bar.corge(a, b, c)
if foo == baz:
return quux
Use 4 spaces to indent instead of 2, which makes it easier to quickly determine which code is in which block.
Prefer for element in my_list instead of for i in range(len(my_list)). If you need the index, in most cases you can use for i, elem in enumerate(my_list). Better yet, use list comprehensions to perform filtering operations, which is most of this logic.
There's no need to use if condition == True. if condition is sufficient. You can simplify confusing and inaccurate logic like:
def palindromes(self):
for i in range(0,len(self.words_list)-1):
normal_word=self.words_list[i]
reversed_word=normal_word[::-1]
if reversed_word==normal_word:
return reversed_word
to, for example:
def palindromes(self):
return [word for word in self.words_list if word[::-1] == word]
that is, avoid intermediate variables and indexes whenever possible.
I realize you're probably tied down to the design, but this strikes me as a strange way to write a utility class. It'd be more flexible as static methods that operate on iterables. Typical usage might be like:
from Wordplay import is_palindrome
is_palindrome(some_iterable)
instead of:
wordplay = Wordplay(some_iterable)
wordplay.palindromes()
My rationale is that this class is basically stateless, so it seems odd to impose state when none is needed. This is a bit subjective, but worth noting (if you've ever used the math or random modules, it's the same idea).
The lack of parameter in the constructor is even weirder; the client of the class has to magically "know" somehow that words_list is the internal variable name they need to make an assignment to in order to populate class state. This variable name should be an implementation detail that the client has no idea about. Failing providing a parameter in the initialization function, there should be a setter for this field (or just skip internal state entirely).
ends_with_s(self, s) is a silly function; it seems the designer is confused between wanting to write ends_with(self, letter) and ends_with_s(self) (the former is far preferable). What if you want a new letter? Do you need to write dozens of functions for each possible ending character ends_with_a, ends_with_b, ends_with_c, etc? I realize it's just a contrived assignment, but the class still exhibits poor design.
Spelling error: words_with_lenght -> words_with_length.
Here's a general tip on how to build the skill at locating these problems: work in very small chunks and run your program often. It appears that these four functions were written all in one go without testing each function along the way to make sure it worked first. This is apparent because the same mistakes were repeated in all four functions.
s.endswith('s') compares your input string s ("s") with "s". "s" ends in "s", so it always returns your first entry. Change it to if self.words_list[i].startswith('s'): (same for endswith).
I would recommend changing your for loops to iterate over the words themselves though:
def ends_with_s(self, s):
for word in self.words_list:
if word.endswith('s'):
return word
Entering a list of values as you described:
amount = int(input("How many words? "))
words = [input("Word {}".format(i + 1)) for i in range(amount)]
What is considered to be a better programming practice when dealing with more object at time (but with the option to process just one object)?
A: LOOP INSIDE FUNCTION
Function can be called with one or more objects and it is iterating inside function:
class Object:
def __init__(self, a, b):
self.var_a = a
self.var_b = b
var_a = ""
var_b = ""
def func(obj_list):
if type(obj_list) != list:
obj_list = [obj_list]
for obj in obj_list:
# do whatever with an object
print(obj.var_a, obj.var_b)
obj_list = [Object("a1", "a2"), Object("b1", "b2")]
obj_alone = Object("c1", "c2")
func(obj_list)
func(obj_alone)
B: LOOP OUTSIDE FUNCTION
Function is dealing with one object only and when it is dealing with more objects in must be called multiple times.
class Object:
def __init__(self, a, b):
self.var_a = a
self.var_b = b
var_a = ""
var_b = ""
def func(obj):
# do whatever with an object
print(obj.var_a, obj.var_b)
obj_list = [Object("a1", "a2"), Object("b1", "b2")]
obj_alone = Object("c1", "c2")
for obj in obj_list:
func(obj)
func(obj_alone)
I personally like the first one (A) more, because for me it makes cleaner code when calling the function, but maybe it's not the right approach. Is there some method generally better than the other? And if not, what are the cons and pros of each method?
A function should have a defined input and output and follow the single responsibility principle. You need to be able to clearly define your function in terms of "I put foo in, I get bar back". The more qualifiers you need to make in this statement to properly describe your function probably means your function is doing too much. "I put foo in and get bar back, unless I put baz in then I also get bar back, unless I put a foo-baz in then it'll error".
In this particular case, you can pass an object or a list of objects. Try to generalise that to a value or a list of values. What if you want to pass a list as a value? Now your function behaviour is ambiguous. You want the single list object to be your value, but the function treats it as multiple arguments instead.
Therefore, it's trivial to adapt a function which takes one argument to work on multiple values in practice. There's no reason to complicate the function's design by making it adaptable to multiple arguments. Write the function as simple and clearly as possible, and if you need it to work through a list of things then you can loop it through that list of things outside the function.
This might become clearer if you try to give an actual useful name to your function which describes what it does. Do you need to use plural or singular terms? foo_the_bar(bar) does something else than foo_the_bars(bars).
Move loops outside functions (when possible)
Generally speaking, keep loops that do nothing but iterate over the parameter outside of functions. This gives the caller maximum control and assumes the least about how the client will use the function.
The rule of thumb is to use the most minimal parameter complexity that the function needs do its job.
For example, let's say you have a function that processes one item. You've anticipated that a client might conceivably want to process multiple items, so you changed the parameter to an iterable, baked a loop into the function, and are now returning a list. Why not? It could save the client from writing an ugly loop in the caller, you figure, and the basic functionality is still available -- and then some!
But this turns out to be a serious constraint. Now the caller needs to pack (and possibly unpack, if the function returns a list of results in addition to a list of arguments) that single item into a list just to use the function. This is confusing and potentially expensive on heap memory:
>>> def square(it): return [x ** 2 for x in it]
...
>>> square(range(6)) # you're thinking ...
[0, 1, 4, 9, 16, 25]
>>> result, = square([3]) # ... but the client just wants to square 1 number
>>> result
9
Here's a much better design for this particular function, intuitive and flexible:
>>> def square(x): return x ** 2
...
>>> square(3)
9
>>> [square(x) for x in range(6)]
[0, 1, 4, 9, 16, 25]
>>> list(map(square, range(6)))
[0, 1, 4, 9, 16, 25]
>>> (square(x) for x in range(6))
<generator object <genexpr> at 0x00000166D122CBA0>
>>> all(square(x) % 2 for x in range(6))
False
This brings me to a second problem with the functions in your code: they have a side-effect, print. I realize these functions are just for demonstration, but designing functions like this makes the example somewhat contrived. Functions typically return values rather than simply produce side-effects, and the parameters and return values are often related, as in the above example -- changing the parameter type bound us to a different return type.
When does it make sense to use an iterable argument? A good example is sort -- the smallest unit of operation for a sorting function is an iterable, so the problem of packing and unpacking in the square example above is a non-issue.
Following this logic a step further, would it make sense for a sort function to accept a list (or variable arguments) of lists? No -- if the caller wants to sort multiple lists, they should loop over them explicitly and call sort on each one, as in the second square example.
Consider variable arguments
A nice feature that bridges the gap between iterables and single arguments is support for variable arguments, which many languages offer. This sometimes gives you the best of both worlds, and some functions go so far as to accept either args or an iterable:
>>> max([1, 3, 2])
3
>>> max(1, 3, 2)
3
One reason max is nice as a variable argument function is that it's a reduction function, so you'll always get a single value as output. If it were a mapping or filtering function, the output is always a list (or generator) so the input should be as well.
To take another example, a sort routine wouldn't make much sense with varargs because it's a classically in-place algorithm that works on lists, so you'd need to unpack the list into the arguments with the * operator pretty much every time you invoke the function -- not cool.
There's no real need for a call like sort(1, 3, 4, 2) as there is with max, where the parameters are just as likely to be loose variables as they are a packed iterable. Varargs are usually used when you have a small number of arguments, or the thing you're unpacking is a small pair or tuple-type element, as often the case with zip.
There's definitely a "feel" to when to offer parameters as varargs, an iterable, or a single value (i.e. let the caller handle looping), but as long as you follow the rule of avoiding iterables unless they're essential to the function, it's hard to go wrong.
As a final tip, try to write your functions with similar contracts to the library functions in your language or the tools you use frequently. These are pretty much always designed well; mimic good design.
If you implement B then you will make it harder for yourself to achieve A.
If you implement A then it isn't too difficult to achieve B. You also have many tools already available to apply this function to a list of arguments (the loop method you described, using something like map, or even a multiprocessing approach if needed)
Therefore I would choose to implement A, and if it makes things neater or easier in a given case you can think about also implementing B (using A) also so that you have both.
I have a method that returns either a list or a tuple. What is the most pythonic way of denoting the return type in the argument?
def names(self, section, as_type=()):
return type(as_type)(([m[0] for m in self.items(section)]))
The pythonic way would be not to care about the type at all. Return a tuple, and if the calling function needs a list, then let it call list() on the result. Or vice versa, whichever makes more sense as a default type.
Even better, have it return a generator expression:
def names(self, section):
return (m[0] for m in self.items(section))
Now the caller gets an iterable that is evaluated lazily. He then can decide to iterate over it:
for name in obj.names(section):
...
or create a list or tuple from it from scratch - he never has to change an existing list into a tuple or vice versa, so this is efficient in all cases:
mylist = list(obj.names(section))
mytuple = tuple(obj.names(section))
Return whatever the caller will want most of the time. If they will want to be able to sort, remove or delete items, etc. then use a list. If they will want to use it as a dictionary key, use a tuple. If the primary use will be iteration, return an iterator. If it doesn't matter to the caller, which it won't more often than you might think, then return whatever makes the code the most straightforward. Usually this will be a list or an iterator.
Don't provide your own way to convert the output to a given type. Python has a perfectly simple way to do this already and any programmer using your function will be familiar with it. Look at the standard Python library. Do any of those routines do this? No, because there's no reason to.
Exception: sometimes there's a way to get an iterator or a list, even though it is easy to convert an iterator to a list. Usually this capability is provided as two separate functions or methods. Maybe you might want to follow suit sometimes, especially if you could implement the two alternatives using different algorithms that provide some clear benefit to callers who want one or another.
Keep it simple:
def names(self, section):
"""Returns a list of names."""
return [m[0] for m in self.items(section)]
If the caller wants a tuple instead of a list, he does this:
names = tuple(obj.names(section))
I want to write a function to create an empty square matrix have size NxN.
I have 2 ways to write this:
1:
s_matrix = []
create_empty_square_matrix(s_matrix, N)
2:
s_matrix = empty_square_matrix(N)
(Ofcourse, 2 two functions will different a bit. Function create_empty_square_matrix is like a procedure - only manipulate on s_matrix. Function empty_square_matrix create & return a matrix)
Which way is more Pythonic & clearer?
Do you have some suggestions about naming style? I'm not sure about empty_square_matrix & create_empty_square_matrix.
I'd always prefer the second way.
The problem with the first is that you pass the object that you want to write to as the paramenter (s_matrix), and the caller of the function will have to know that it must be passed an empty list. What happens if the caller passes a dict, or a list that is not empty?
By the way, if you want to do matrix calculations, you should take a look at the NumPy library, it offers many things that standard Python does not.
i wanted to do something like this but this code return list of None (i think it's because list.reverse() is reversing the list in place):
map(lambda row: row.reverse(), figure)
i tried this one, but the reversed return an iterator :
map(reversed, figure)
finally i did something like this , which work for me , but i don't know if it's the right solution:
def reverse(row):
"""func that reverse a list not in place"""
row.reverse()
return row
map(reverse, figure)
if someone has a better solution that i'm not aware of please let me know
kind regards,
The mutator methods of Python's mutable containers (such as the .reverse method of lists) almost invariably return None -- a few return one useful value, e.g. the .pop method returns the popped element, but the key concept to retain is that none of those mutators returns the mutated container: rather, the container mutates in-place and the return value of the mutator method is not that container. (This is an application of the CQS principle of design -- not quite as fanatical as, say, in Eiffel, the language devised by Bertrand Meyer, who also invented CQS, but that's just because in Python "practicality beats purity, cfr import this;-).
Building a list is often costlier than just building an iterator, for the overwhelmingly common case where all you want to do is loop on the result; therefore, built-ins such as reversed (and all the wonderful building blocks in the itertools module) return iterators, not lists.
But what if you therefore have an iterator x but really truly need the equivalent list y? Piece of cake -- just do y = list(x). To make a new instance of type list, you call type list -- this is such a general Python idea that it's even more crucial to retain than the pretty-important stuff I pointed out in the first two paragraphs!-)
So, the code for your specific problem is really very easy to put together based on the crucial notions in the previous paragraphs:
[list(reversed(row)) for row in figure]
Note that I'm using a list comprehension, not map: as a rule of thumb, map should only be used as a last-ditch optimization when there is no need for a lambda to build it (if a lambda is involved then a listcomp, as well as being clearer as usual, also tends to be faster anyway!-).
Once you're a "past master of Python", if your profiling tells you that this code is a bottleneck, you can then know to try alternatives such as
[row[::-1] for row in figure]
applying a negative-step slicing (aka "Martian Smiley") to make reversed copies of the rows, knowing it's usually faster than the list(reversed(row)) approach. But -- unless your code is meant to be maintained only by yourself or somebody at least as skilled at Python -- it's a defensible position to use the simplest "code from first principles" approach except where profiling tells you to push down on the pedal. (Personally I think the "Martian Smiley" is important enough to avoid applying this good general philosophy to this specific use case, but, hey, reasonable people could differ on this very specific point!-).
You can also use a slice to get the reversal of a single list (not in place):
>>> a = [1,2,3,4]
>>> a[::-1]
[4, 3, 2, 1]
So something like:
all_reversed = [lst[::-1] for lst in figure]
...or...
all_reversed = map(lambda x: x[::-1], figure)
...will do what you want.
reversed_lists = [list(reversed(x)) for x in figure]
map(lambda row: list(reversed(row)), figure)
You can also simply do
for row in figure:
row.reverse()
to change each row in place.