Python converting nested loops to simple line - python

In Python 2.7.x I have two lists I would like a function that returns the first value (not index) as shown below
def first_incorrect_term(polynomial, terms):
for index in range(len(polynomial), len(terms)):
if evaluate(polynomial, index) != terms[index-1]:
return evaluate(polynomial, index)
Let us assume evaluate is a function that works. I would like to replace these three lines which looks Object Oriented into something that uses the "find" or some such function in Python.
Basically I am iterating through the indices of the second list beyond the number terms in the polynomial (as I am confident the first X terms will match), evaluating it and comparing with the expected terms. For the first instance where the terms do not match I would like the evaluated polynomial returned.
I am looking for a replacement of these 3 lines using a Python find/lambda or some such thing, this is because I can definitely see I am not using the Python power as described for example in the link
PS: This is somewhat related to a Project Euler problem, however I have solved it using the snippet above and would like to improve my "Python" skills :)

Firstly, use yield to make a generator version of your function:
def incorrect_terms(polynomial, terms):
for index in range(len(polynomial), len(terms)):
eval = evaluate(polynomial,index)
if eval != terms[index-1]:
yield (polynomial, index, eval)
Then the first result is the first mismatch:
mismatches = incorrect_terms(polynomial, terms)
first_mismatch = mismatches.next()
I think you actually want to iterate over all the values of terms, not the values after polynomial's length, in which case you can zip:
results = (evaluate(polynomial,index) for index in count(0))
pairsToCompare = itertools.izip(results, terms)
mismatches = (pair for pair in pairsToCompare if pair[0] != pair[1])
first_mismatch = mismatches.next()
Assuming here that evaluate(polynomial, n) is calculating the nth term for a given polynomial, and that these are being compared with the values in terms.

I would do it using generator expressions, but they don't fit in one line as well:
def first_incorrect_term(polynomial, terms):
evaled = ((index, evaluate(polynomial, index)) for index in range(len(polynomial), len(terms)))
return next((val for index, val in evaled if val != terms[index-1]), None)

Related

Finding the shortest word in a string

I'm new to coding and I'm working on a question that asks to find the shortest word within a sentence. I'm confused what the difference between:
def find_short(s):
for x in s.split():
return min(len(x))
and
def find_short(s):
return min(len(x) for x in s.split())
is, because the former gives me an error and the latter seems to work fine. Are they not virtually the same thing?
Are they not virtually the same thing?
No, they are not the same thing. If s equals "hello world", in the first iteration, x would be "hello". And there are two things wrong here:
You are trying to return in the very first iteration rather than going over all the elements (words) to find out what's the shortest.
min(len(x)) is like saying min(5) which is not only an bad parameter to pass to min(..) but also doesn't make sense. You'd want to pass a list of elements from which min will calculate the minimum.
The second approach is actually correct. See this answer of mine to get an idea of how to interpret it. In short, you are calculating length of every word, putting that into a list (actually a generator), and then asking min to run its minimum computation on it.
There's an easier approach to see why your second expression works. Try printing the result of the following:
print([len(x) for x in s.split()])
The function min takes an array as parameter.
On your 1st block, you have
def find_short(s):
for x in s.split():
return min(len(x))
min is called once on the length of the 1st word, so it crashes because it's expecting an array
You second block is a little different
def find_short(s):
return min(len(x) for x in s.split())
Inside min, you have len(x) for x in s.split() which will return an array of all the lengths and give it to min. Then, with this array, min will be able to return the smallest.
No, they are not the same thing.
In first piece of code you are entering for cycle and trying to calculate min of the first word's length. min(5) doesn't make sense, does it? And even if it could be calculated, return would have stopped executing this function (other words' lengths would not have been taken into consideration).
In second one, len(x) for x in s.split() is a generator expression yielding the lengths of all the words in your sentence. And min will calculate the minimal element of this sequence.
Yes, the examples given are very different.
The first example effectively says:
Take the string s, split it by spaces, and then take each word, x, found and return the minimum value of just the length of x.
The second example effectively says:
Find the minimum value in the list generated by len(x) for x in s.split().
That first example generates an error because the min function expects to compare at least 2 or more elements, and only 1 is provided.
That second example works because the list that is generated by len(x) for x in s.split() converts a string, like say "Python types with ducks?" to a list of word lengths (in my example, it would convert the string to [6, 5, 4, 6]). That list that is generated (this is also why it's called a generator), is what the min function then uses to find the minimum value inside said list.
Another way to write that first example so that it works like you would expect is like this
def find_short(s):
min_length = float("inf")
for x in s.split():
if len(x) < min_length:
min_length = len(x)
return min_length
However, notice how you have to keep track of a variable that you do not have to define using the list generator method in your second example. Although this is not a big deal when you are learning programming for the first time, it becomes a bigger deal when you start making larger, more complex programs.
Sidenote:
Any value that follows the return keyword is what a function "outputs", and thus no more code gets executed.
For example, in your first example (and assuming that the error was not generated), your loop would only ever execute once regardless of the string you give it because it does not check that you actually have found the value you want. What I mean by that is that any time your code encounters a return statement, it means that your function is done.
That is why in my example find_short function, I have an if statement to check that I have the value that I want before committing to the return statement that exits the function entirely.
There is mainly two mistakes here.
First of, seems you are returning the length of the string, not the string itself.
So your function will return 4 instead of 'book', for example.
I will get into how you can fix it in short.
But answering your question:
min() is a function that expects an iterable (entities like array).
In your first method, you are splitting the text, and calling return min(len(word)) for each word.
So, if the call was successfully, it would return on the first iteration.
But it is not successfully because min(3) throws an exception, 3 is not iterable.
On your second approach you are creating a list of parameters to min function.
So your code first resolves len(x) for x in s.split() returning something like 3,2,3,4,1,3,5 as params for min, which returns the minimum value.
If you would like to return the shortest word, you could try:
def find_short(s):
y = s.split()
y.sort(key=lambda a: len(a))
return y[0]

Quicksort ascending and descendding python

I am trying to implement quicksort in place in ascending and descending order. The pivot element is the middle one. If the list is length 2 the pivot element is the first one. if the list length is even the pivot element is the last number of the first half of list. I have written a function which is called
quickSort(L, ascending True) L = List, true=ascending, false=descending
quickSort(testList1,False)
def quickSort(L, ascending = True):
print('Quicksort, Parameter L:')
print(L)
def quicksort(listToSort,lowIndex,highIndex):
if ((highIndex - lowIndex) > 0):
p = partition(listToSort,lowIndex,highIndex)
quicksort(listToSort,lowIndex,p-1)
quicksort(listToSort,p+1,highIndex)
def partition(listToSort, lowIndex, highIndex):
divider = lowIndex
pivot = highIndex
for i in range(lowIndex,highIndex):
if (listToSort[i] < listToSort[pivot]):
listToSort[i], listToSort[divider] = listToSort[divider],listToSort[i]
divider +=1
listToSort[pivot], listToSort[divider] = listToSort[divider], listToSort[pivot]
return divider
testList1 = [1,0,2,3,4,6,5,8,9,7]
testList2 = list([3.14159 , 1./127, 2.718 , 1.618 , -23., 3.14159])
testList3 = [10,9,8,7,6,5,4,3,2,1]
quicksort(testList1,0,9)
print (testList1)
quicksort(testList2,0,5)
print (testList2)
quicksort(testList3,0,9)
print (testList3)
quickSort(testList1,False)
The idea behind quick sort is partitioning a list into values that are less than a target value and the values greater than the target value. I used Haskell for the algorithm because algorithms can be directly expressed in Haskell. I then tried to translate it into Python. This turned into was more coding than I am accustomed to, to accomplish minor tasks.
In Haskell, it was necessary to import partition from Data.List
partition takes a list and produces 2 parts according to a supplied predicate. The predicate, in this case, is only <=nv because it is implied that each successive element of a list will be used as an argument. Haskell, like Python, can assign multiple values at a time.
The two parts of the partition output are bound to variables 'b' for beginning and 'e' for end because I am not very creative.
The word where is as in math.
b is concatenated with the insertion value which is then concatenated to 'e'
Haskell has functions that operate on functions. I give this function to foldr with required parameters. foldr uses the supplied function recursively with successive accumulated values.
The function is
ft nv ls = b++[nv]++e where (b,e) = partition (<=nv) ls
Executing it with foldr and it sorts the list. Place the reverse function in front of it for a reversed sorted list.
foldr ft [] [5,4,3,2,1,0,9,8,7,6]
Edit 6-21-2018\
I was trying to make the Python version recursive but failed. In Python, the iterative version came too easily. The two filter functions do the same thing as the partition function in Haskell.
def isort(ls):
nls=ls
for i in ls:
nls= filter(lambda x: x<i,nls) +[i]+ filter(lambda x: x>i,nls)
return(nls)

Quick Sort using Python

I was wondering if someone can help me to fix the error my code for quick sort has:
It does not compile and highlights the last line of the code in red.
I can not figure out what is wrong. sort is already defined as a function so why is it highlighted as red?
def sort(*myarray):
less = []
equal = []
greater = []
if len(myarray) > 1:
pivot = myarray[0]
for x in myarray:
if x < pivot:
less.append(x)
if x == pivot:
equal.append(x)
if x > pivot:
greater.append(x)
return sort(less)+sort(equal)+sort(greater)
else:
return myarray
print sort([12,4,5,6,7,3,1,15])
You're defining the function as taking a variable number of arguments (the *myarray bit), but then using myarray inside as a single argument (the list to sort), when it is a list containing the list to sort.
You probably should remove the * from your function parameter. This questions esplains it quite thoroughly.
You could keep the *, but then you would have to play a bit with tuple unpacking to get the same result.
edit
Although the above is true, this might not be the issue you're encountering.
IDLE will give you the invalid syntax error on the ast line, because in interactive mode - with lines starting with >>>, it accepts only one statement at a time. In your case that statement is the sort() definition.
Try hitting enter 2 times after the function definition, this should get you back to the repl, where you can introduce another statement (print sort([12,4,5,6,7,3,1,15]))
There are a couple things wrong which makes me curious how you are testing this:
Python code is not "compiled", it is interpreted. (Okay, not precisely true; it's parsed into a sort of byte-code; still, it's not compiled in the same sense as a language such as C, where the entire program has to be converted into machine instructions before any of it can be run.) Also you mention the last line of code is highlighted in red -- by what?
This code actually works, but only if you remote the star/asterisk in front of myarray in def sort(*myarray):. Otherwise it actually returns a single-element tuple containing the original array.
Assuming you have two or more elements that equal a pivot at some point, you get an infinite loop, because you will get: equal = [x,x] (two elements at least), and then invoke sort([x,x]), which in its turn will take x as a pivot, and create equal = [x,x], and cause sort([x,x]), ....
Simple solution to this problem: What should be the output of the sort(equal)? How do you sort a list of identical elements?
Edit: Well, your comments show that you are looking for a different problem, but I'll leave it here because it explains a different issue you have with your code and should be solved.
If it is a function for quick sorting, can you really use the function sort in it?
Wouldn't something like this work?
def qsort(list):
pivind=0
left, right, pivot= [], [], []
for x in list:
if list[pivind]==x: pivot.append(x)
elif list[pivind]>x: left.append(x)
else: right.append(x)
if len(left)>1: left=qsort(left)
if len(right)>1: right=qsort(right)
return (left + pivot + right)

python nested generator objects content

I have a problem with Python.
I'm trying to understand which are the information stored in an object that I discovered be a generator.
I don't know anything about Python, but I have to understand how this code works in order to convert it to Java.
The code is the following:
def segment(text):
"Return a list of words that is the best segmentation of text."
if not text: return []
candidates = ([first]+segment(rem) for first,rem in splits(text))
return max(candidates, key=Pwords)
def splits(text, L=20):
"Return a list of all possible (first, rem) pairs, len(first)<=L."
pairs = [(text[:i+1], text[i+1:]) for i in range(min(len(text), L))]
return pairs
def Pwords(words):
"The Naive Bayes probability of a sequence of words."
productw = 1
for w in words:
productw = productw * Pw(w)
return productw
while I understood how the methods Pwords and splits work (the function Pw(w) simply get a value from a matrix), I'm still trying to understand how the "candidates" object, in the "segment" method is built and what it contains.
As well as, how the "max()" function analyzes this object.
I hope that someone could help me because I didn't find any feasible solution here to print this object.
Thanks a lot to everybody.
Mauro.
generator is quite simple abstraction. It looks like single-use custom iterator.
gen = (f(x) for x in data)
means that gen is iterator which each next value is equal to f(x) where x is corresponding value of data
nested generator is similar to list comprehension with small differences:
it is single use
it doesn't create whole sequence
code runs only during iterations
for easier debugging You can try to replace nested generator with list comprehension
def segment(text):
"Return a list of words that is the best segmentation of text."
if not text: return []
candidates = [[first]+segment(rem) for first,rem in splits(text)]
return max(candidates, key=Pwords)

Python: Using find function not in order

So the code below takes a string of inputted information (A math expression), and uses the find function to find one of the operators in "*/+-" and separates the string accordingly.
def splitting1(z):
for operators in "*/+-":
if operators in z:
position1= z.find(operators)
position2= z.rfind(operators)
text_before_operators= (z[:position1]).strip()
text_after_operators= (z[(position1+1):(position2)]).strip()
return text_before_operators,text_after_operators
My problem is that if I have an inputted expression such as 3/5*7 then position1 will first find * before finding /. I want the code to associate 'position1' with the left most operator. Is there a way to omit operator precedence when using the for/in functions? If not, is there a better string manipulator that can omit the order of precedence.
Note z is the input. And the input is limited to two operators in case that created ambiguity.
You're iterating over */+-, so the first character that's found is the first one that's returned.
You basically want to find the indexes of all of these operators and then find the largest or the smallest. Try re-writing this function to work for other side of the string:
def find_operator_right(text):
position = -1
for oper in '*/+-':
index = text.rfind(oper)
if index > position:
position = index
return position
A slightly more Pythonic solution would be something like this:
right_index = max(map(text.rfind, '+-/*'))
It looks like you are trying to lex, so I suggest you look into modules designed especially for this purpose, for example ply.
.
Saying that, I think you are on the right track for this example, but you are missing some recursion (to make a more general lexer for these):
def splitting1(z):
for char in "*/+-":
if char in z:
position = z.find(char)
text_before_operator= (z[:position]).strip()
text_after_operator= (z[position+1:]).strip()
return (char, splitting1(text_before_operator), splitting1(text_after_operator))
return ("number", z)
One way to find the left-most operator regardless of precedence i.e. omit operator precedence, is to rearrange what you iterate over:
def splitting2(z):
for char in z:
if char in "*/+-":
position = z.find(char)
text_before_operator= (z[:position]).strip()
text_after_operator= (z[position+1:]).strip()
return (char, splitting2(text_before_operator), splitting2(text_after_operator))
return ("number", z)
Note these function return a different result to your original function.

Categories

Resources