Is there a way to find a max value between a range? - python

For example,
l = [1, -9, 2, 5, 9, 16, 11, 0, 21]
and if the range is 10 (10 meaning any numbers higher than 10 wont be considered as the max), I want the code to return 9.

You can first delete all elements too large and then find the max:
filtered = filter(lambda x: x <= limit, list)
val = max(filtered, default = None) # the `default` part means that that's returned if there are no elements
filtered is a filter object which contains all elements less than or equal to the limit. val is the maximum value in that.
Alternatively,
filtered = [x for x in list if x <= limit]
val = max(filtered, default = None)
filtered contains all elements in the list if and only if they are less than the limit. val is the maximum of filtered.
Alternatively,
val = max((x for x in list if x <= limit), default = None)
This combines the two steps from the above method by using an argument comprehension.
Alternatively,
val = max(filter(limit.__ge__, list), default = None)
limit.__ge__ is a function that means x => limit >= x (ge means Greater-Equal). This is the shortest and least readable way of writing it.
Also please rename list
list is a global variable (the list type in Python). Please don't overwrite global variables ;_;

The following is not radically different, conceptually, than #HyperNeutrino's excellent answer, but I think it's somewhat clearer (per the Zen):
from __future__ import print_function
l = [1, -9, 2, 5, 9, 16, 11, 0, 21]
def lim(x, n):
if x <= n:
return x
print(max(lim(a,10) for a in l))

The cleanest and most space efficient method is to utilize a conditioned generator expression:
maxl = max(num for num in l if num <= 10)
This loops over the list l once, ignoring any numbers not satisfying num <= 10 and finds the maximum. No additional list is build.

Related

How to return the first item rather than the entire list, using list comprehension?

I'm solving a problem where I must find an unique integer in a list, which is easily solvable using list.count(x). However, I'm having trouble condensing the code into one line.
def find_uniq(arr):
return [x for x in arr if arr.count(x) == 1]
My code works fine, but it returns for example: [2] instead of 2, or [0.55] instead of 0.55.
Is there a way to return the integer instead of the list containing the integer, using list comprehension?
You have already the answers for list-comprehension -- which is a waste of resources.
Your approach, though, is valid since it makes use of everyday/beginner structures. In the same argument, I would like to suggest two things:
avoid the redundant calls to count();
avoid the creation of a list (since all you want is one element a time).
Suppose we have the following array arr:
> arr = [random.randint(0,9) for _ in range(10)]
> arr
[6, 7, 0, 9, 3, 3, 3, 9, 8, 8]
To the first point, you can create a set to reduce the number of counts:
> numbers_set = set(arr)
> numbers_set
{0, 3, 6, 7, 8, 9}
Then you can have a generator with the help of our friend filter:
> unique_numbers = filter(lambda x:arr.count(x)==1, numbers_set)
> print(next(unique_numbers))
0
> print(next(unique_numbers))
6
> print(next(unique_numbers))
7
> print(next(unique_numbers))
StopIteration:
Instead of a list comprehension which produces a list, create a generator from which you take the first element:
return next(x for x in arr if arr.count(x) == 1)
This raises a StopIteration is no element in the list fulfils the criteria; you can instead return a default value like None like so:
return next((x for x in arr if arr.count(x) == 1), None)
It's also questionable whether it's wise to iterate the array again and again with count; depending on its size, that can be very inefficient. It may be more efficient to build a counter first:
from collections import Counter
return next(v for v, c in Counter(arr).items() if c == 1)
If you are sure that You want to return only one integer from the passed list You can change the return to
def find_uniq(arr):
return [x for x in arr if arr.count(x) == 1][0]
But it will return only first element that is unique in the list. If You want to return more of them the list is better approach
Return using indexing.
def find_uniq(arr):
return [x for x in arr if arr.count(x) == 1][0]

Writing a function that alternates plus and minus signs between list indices

In a homework set I'm working on, I've come across the following question, which I am having trouble answering in a Python-3 function:
"Write a function alternate : int list -> int that takes a list of
numbers and adds them with alternating sign. For example alternate
[1,2,3,4] = 1 - 2 + 3 - 4 = -2."
Full disclosure, the question was written with Standard ML in mind but I have been attempting to learn Python and came across the question. I'm imagining it involves some combination of:
splitting the list,
if [i] % 2 == 0:
and then concatenating the alternate plus and minus signs.
def alternate(l):
return sum(l[::2]) - sum(l[1::2])
Take the sum of all the even indexed elements and subtract the sum of all the odd indexed elements. Empty lists sum to 0 so it coincidently handles lists of length 0 or 1 without code specifically for those cases.
References:
list slice examples
sum()
Not using fancy modules or operators since you are learning Python.
>>> mylist = range(2,20,3)
>>> mylist
[2, 5, 8, 11, 14, 17]
>>> sum(item if i%2 else -1*item for i,item in enumerate(mylist, 1))
-9
>>>
How it works?
>>> mylist = range(2,20,3)
>>> mylist
[2, 5, 8, 11, 14, 17]
enumerate(mylist, 1) - returns each item in the list and its index in the list starting from 1
If the index is odd, then add the item. If the index is even add the negative of the item.
if i%2:
return item
else:
return -1*item
Add everything using sum bulitin.
>>> sum(item if i%2 else -1*item for i,item in enumerate(mylist, 1))
-9
>>>
Although this already has an accepted answer I felt it would be better to also provide a solution that isn't a one-liner.
def alt_sum(lst):
total = 0
for i, value in enumerate(lst):
# checks if current index is odd or even
# if even then add, if odd then subtract
if i % 2 == 0:
total += value
else:
total -= value
return total
>>> alt_sum([1, 2, 3, 4])
-2
my_list = range(3, 20, 2)
sum(item * ((-1)**index) for index, item in enumerate(my_list))
sum = 11 (result of 3-5+7-9+11-13+15-17+19)
You could try this list comprehension:
sum([-e if c%2 else e for c,e in enumerate(yourlistylist)])
Here is one way using operator module:
In [21]: from operator import pos, neg
In [23]: ops = (pos, neg)
In [24]: sum(ops[ind%2](value) for ind, value in enumerate(lst))
Out[24]: -2
You can use cycle from itertools to alternate +/-
>>> from itertools import cycle
>>> data = [*range(1, 5)]
>>> sum(i * s for i, s in zip(data, cycle([1, -1])))
-2

Given an odd length list of values in Python, how can I swap all values other than the final value in the list?

In regards to Python 2.7.12 (disclaimer: I understand Python2 is being phased out to Python3, but the course I'm taking started us here, perhaps to understand older code bases):
I have a list of integers whom I'd like to swap each with their neighboring value. So far, this works great for lists that are even in the number of integers they contain, however when the list length is odd, it's not so easy to simply swap each value, as the number of integers is uneven.
Giving the following code example, how can I swap all values other than the final value in the list?
arr = [1, 2, 3, 4, 5]
def swapListPairs(arr):
for idx, val in enumerate(arr):
if len(arr) % 2 == 0:
arr[idx], arr[val] = arr[val], arr[idx] # traditional swap using evaluation order
else:
arr[0], arr[1] = arr[1], arr[0] # this line is not the solution but where I know I need some conditions to swap all list values other than len(arr)-1, but am not sure how to do this?
return arr
print swapListPairs(arr)
Bonus Points to the ultimate Pythonic Master: How can this code be modified to also swap strings? Right now, I can only use this function using integers and am very curious how I can make this work for both int and str objects?
Thank you so greatly for any insight or suggestions to point me in the right direction! Everyone's help at times here has been invaluable and I thank you for reading and for your help!
Here's a shorter, probably faster way based on slice assignment:
def swap_adjacent_elements(l):
end = len(l) - len(l) % 2
l[:end:2], l[1:end:2] = l[1:end:2], l[:end:2]
The slice assignment selects the elements of l at all even indices (l[:end:2]) or all odd indices (l[1:end:2]) up to and excluding index end, then uses the same kind of swapping technique you're already using to swap the slices.
end = len(l) - len(l) % 2 selects the index at which to stop. We set end to the closest even number less than or equal to len(l) by subtracting len(l) % 2, the remainder when len(l) is divided by 2.
Alternatively, we could have done end = len(l) & ~1, using bitwise operations. That would construct an integer to use as a mask (~1), with a 0 in the 1 bit and 1s everywhere else, then apply the mask (with &) to set the 1 bit of len(l) to 0 to produce end.
This is easier to do without enumerate. Note that it never, ever makes decisions based on the contents of arr; that is what makes it work on anything, not just a pre-sorted list of integers starting from 1.
for i in range(len(arr)//2):
a = 2*i
b = a+1
if b < len(arr):
arr[a], arr[b] = arr[b], arr[a]
Exercise for you: is the if actually necessary? Why or why not?
You could iterate through the length of the list with a step of two and try to swap values (and except index errors).
def swap_list_pairs(arr):
for index in range(0, len(arr), 2):
try:
arr[index], arr[index+1] = arr[index+1], arr[index]
except IndexError:
pass
return arr
This will work for all data types.
As Copperfield suggested, you could get rid of the try-except-clause:
def swap_list_pairs(arr):
for index in range(1, len(arr), 2):
arr[index-1], arr[index] = arr[index], arr[index-1]
return arr
Similar to #user2357112 but I prefer it this way:
arr[1::2], arr[:-1:2] = arr[:-1:2], arr[1::2]
Demo:
>>> arr = [1, 2, 3, 4, 5]
>>> arr[1::2], arr[:-1:2] = arr[:-1:2], arr[1::2]
>>> arr
[2, 1, 4, 3, 5]
>>> arr = [1, 2, 3, 4, 5, 6]
>>> arr[1::2], arr[:-1:2] = arr[:-1:2], arr[1::2]
>>> arr
[2, 1, 4, 3, 6, 5]
looks like : and :: confuse you a little, let me explain it:
Sequences type of object in python such as list, tuple, str, among other provide what is know as a slice, it come in 2 flavors:
Slicing: a[i:j] selects all items with index k such that i <= k < j. When used as an expression, a slice is a sequence of the same type. This implies that the index set is renumbered so that it starts at 0.
Extended slicing with a third “step” parameter: a[i:j:k] selects all items of a with index x where x = i + n*k, n >= 0 and i <= x < j.
In both cases i, j and/or k can be omitted and in that case suitable values are used instead
Some examples
>>> arr = [10, 20, 30, 40, 50, 60, 70]
>>> arr[:]
[10, 20, 30, 40, 50, 60, 70]
>>> arr[:3]
[10, 20, 30]
>>> arr[1:3]
[20, 30]
>>> arr[1::2]
[20, 40, 60]
>>> arr[::2]
[10, 30, 50, 70]
>>>
the working of this can also be illustrated with the following function
def the_slice(lista, ini=None, end=None, step=None):
result=[]
if ini is None:
ini = 0
if end is None:
end = len(lista)
if step is None:
step = 1
for index in range(ini,end,step):
result.append( lista[index] )
return result
>>> the_slice(arr,step=2) # arr[::2]
[10, 30, 50, 70]
>>> the_slice(arr,ini=1,step=2) # arr[1::2]
[20, 40, 60]
>>>

Create range without certain numbers

I want to create a range x from 0 ... n, without any of the numbers in the list y. How can I do this?
For example:
n = 10
y = [3, 7, 8]
x = # Do Something
Should give the output:
x = [0, 1, 2, 4, 5, 6, 9]
One naive way would be to concatenate several ranges, each spanning a set of numbers which have been intersected by the numbers in y. However, I'm not sure of what the simplest syntax to do this is in Python.
You can use a list comprehension to filter the range from 0 to n: range(n) generates a list (or, in Python 3, a generator object) from 0 to n - 1 (including both ends):
x = [i for i in range(n) if i not in y]
This filters out all numbers in y from the range.
You can also turn it into a generator (which you could only iterate over once but which would be faster for (very) large n) by replacing [ with ( and ] with ). Further, in Python 2, you can use xrange instead of range to avoid loading the entire range into memory at once. Also, especially if y is a large list, you can turn it into a set first to use O(1) membership checks instead of O(n) on list or tuple objects. Such a version might look like
s = set(y)
x = (i for i in range(n) if i not in s)
hlt's answer is ideal, but I'll quickly suggest another way using set operations.
n = 10
y = [3, 7, 8]
x = set(range(n)) - set(y)
x will be a set object. If you definitely need x to be a list, you can just write x = list(x).
Note that the ordering of a set in Python is not guaranteed to be anything in particular. If order is needed, remember to sort.
Adding on to the above answers, here is my answer using lambda function:
x = filter(lambda x: x not in y,range(n))

Getting the indices of the X largest numbers in a list

Please no built-ins besides len() or range(). I'm studying for a final exam.
Here's an example of what I mean.
def find_numbers(x, lst):
lst = [3, 8, 1, 2, 0, 4, 8, 5]
find_numbers(3, lst) # this should return -> (1, 6, 7)
I tried this not fully....couldn't figure out the best way of going about it:
def find_K_highest(lst, k):
newlst = [0] * k
maxvalue = lst[0]
for i in range(len(lst)):
if lst[i] > maxvalue:
maxvalue = lst[i]
newlst[0] = i
Take the first 3 (x) numbers from the list. The minimum value for the maximum are these. In your case: 3, 8, 1. Their index is (0, 1, 2). Build pairs of them ((3,0), (8,1), (1,2)).
Now sort them by size of the maximum value: ((8,1), (3,0), (1,2)).
With this initial List, you can traverse the rest of the list recursively. Compare the smallest value (1, _) with the next element in the list (2, 3). If that is larger (it is), sort it into the list ((8,1), (3,0), (2,3)) and throw away the smallest.
In the beginning you have many changes in the top 3, but later on, they get rare. Of course you have to keep book about the last position (3, 4, 5, ...) too, when traversing.
An insertion sort for the top N elements should be pretty performant.
Here is a similar problem in Scala but without the need to report the indexes.
I dont know is it good to post a solution, but this seems to work:
def find_K_highest(lst, k):
# escape index error
if k>len(lst):
k=len(lst)
# the output array
idxs = [None]*k
to_watch = range(len(lst))
# do it k times
for i in range(k):
# guess that max value is at least at idx '0' of to_watch
to_del=0
idx = to_watch[to_del]
max_val = lst[idx]
# search through the list for bigger value and its index
for jj in range(len(to_watch)):
j=to_watch[jj]
val = lst[j]
# check that its bigger that previously finded max
if val > max_val:
idx = j
max_val = val
to_del=jj
# append it
idxs[i] = idx
del to_watch[to_del]
# return answer
return idxs
PS I tried to explain every line of code.
Can you use list methods? (e.g. append, sort, index?). If so, this should work (I think...)
def find_numbers(n,lst):
ll=lst[:]
ll.sort()
biggest=ll[-n:]
idx=[lst.index(i) for i in biggest] #This has the indices already, but we could have trouble if one of the numbers appeared twice
idx.sort()
#check for duplicates. Duplicates will always be next to each other since we sorted.
for i in range(1,len(idx)):
if(idx[i-1]==idx[i]):
idx[i]=idx[i]+lst[idx[i]+1:].index(lst[idx[i]]) #found a duplicate, chop up the input list and find the new index of that number
idx.sort()
return idx
lst = [3, 8, 1, 2, 0, 4, 8, 5]
print find_numbers(3, lst)
Dude. You have two ways you can go with this.
First way is to be clever. Phyc your teacher out. What she is looking for is recursion. You can write this with NO recursion and NO built in functions or methods:
#!/usr/bin/python
lst = [3, 8, 1, 2, 0, 4, 8, 5]
minval=-2**64
largest=[]
def enum(lst):
for i in range(len(lst)):
yield i,lst[i]
for x in range(3):
m=minval
m_index=None
for i,j in enum(lst):
if j>m:
m=j
m_index=i
if m_index:
largest=largest+[m_index]
lst[m_index]=minval
print largest
This works. It is clever. Take that teacher!!! BUT, you will get a C or lower...
OR -- you can be the teacher's pet. Write it the way she wants. You will need a recursive max of a list. The rest is easy!
def max_of_l(l):
if len(l) <= 1:
if not l:
raise ValueError("Max() arg is an empty sequence")
else:
return l[0]
else:
m = max_of_l(l[1:])
return m if m > l[0] else l[0]
print max_of_l([3, 8, 1, 2, 0, 4, 8, 5])

Categories