Creating range objects in python - python-3.5

Is there a way to create objects or tuples in python which represent range.
I need to check whether a variable is within some range.
e.g.
Instead of doing:
a = 2
if a > -1 and a < 5:
print (a)
I would like to do:
if a in [-1, 5]:
print(a)

One of the beauties of Python:
a=2
if -1 <= a <= 5:
print(a)

Related

How to reassign multiple variables (if possible) with an iterator in Python 3

update Adding a usage example to better explain why I'm trying to elicit this behavior. See update at end of post. Added better syntax for links and added a link to article suggested as an answer.
I am trying to use an iterator to alter the value of a list of variables.
>>> a = 1
>>> b = 2
>>> c = 3
>>> for i in [a,b,c]:
i += 1
>>> a,b,c #Expecting (2, 3, 4)
(1, 2, 3)
This doesn't appear to work, I've tried some other ways (see below) without success.
1. Will someone please tell me a better way to approach this problem?
2. Will someone explain why the example above doesn't work as I expected?
3. Will someone tell me how/where I could have found #2 in python help documentation?
Places I've previously looked for answers...
StackOverflow question "reassign variable to original value defined prior to the loop at start of each"
StackOverflow question on reassigning variables (but not a list of variables)
Python docs: Objects and Value Types
Python docs section 3.1.3
I feel like the last reference to the python docs might have the answer, but I was overwhelmed with the amount of info, my brain is tired, and I'm hoping someone on s.o. can help.
also tried...
>>> help(__name__)
Help on module __main__:
NAME
__main__
DATA
__annotations__ = {}
a = 1
b = 2
c = 3
i = 4
FILE
(built-in)
but if anything, this only confused me further.
Lastly I tried...
>>> a = 1
>>> b = 2
>>> c = 3
>>> R = [a, b, c]
>>> for i in range(3):
R[i] += 1
>>> a, b, c #Hoping for (2, 3, 4)
(1, 2, 3)
>>> R #Kind of expected (1, 2, 3) based on the above behavior
[2, 3, 4]
update
I used the list for convenience, since I could iterate through its members. The part I'm not understanding is that when I say...
>>> x = [a, b, c]
I am creating a list such that
x = [the value assigned to a,
the value assigned to b,
the value assigned to c]
rather than
x = [the variable a, the variable b, the variable c]
so when I am trying to use the syntax
>>> x[0] += 1 #take the current ITEM in place 0 and increment its value by 1.
instead of
>>> a += 1
it is instead interpreted as...
take the current VALUE of the ITEM in place 0,
increment that VALUE by 1,
this is the new VALUE of ITEM in place 0 ...
and I lose the reference to the original ITEM... the variable a.
Here is a usage example of why I am trying to elicit this behavior...
>>> class breakfast():
>>> def __init__(self, eggs=None, bacon=None, spam=None):
>>> self.eggs = eggs
>>> self.bacon = bacon
>>> self.spam = spam
>>> updateOrder = False
>>> updateItems = []
>>> for i in [self.eggs, self.bacon, self.spam]:
>>> if i == None:
>>> updateOrder = True
>>> updateItems.append(i)
>>> else:
>>> pass
>>> if updateOrder:
>>> self.updateOrder(itemsToUpdate = updateItems)
>>>
>>> def updateOrder(self, itemsToUpdate):
>>> for i in itemsToUpdate: ###also tried...
>>> ###for i in range(len(itemsToUpdate)):
>>> print('You can\'t order None, so I am updating your order to 0 for some of your items.')
>>> i = 0
>>> ###itemsToUpdate[i] = 0
>>>
>>> #Finally, the good part, behavior I'm after...
>>> myBreakfast = breakfast(eggs=2,bacon=3)
You can't order None, so I am updating your order to 0 for some of your items.
>>> myBreakfast.spam == 0 #hoping for True....
False
The only way I know would work to get this behavior is to instead say...
>>> ...
>>> def updateOrder(self):
>>> orderUpdated=False
>>> if self.eggs == None:
>>> self.eggs = 0
>>> orderUpdated = True
>>> if self.bacon == None:
>>> self.bacon = 0
>>> orderUpdated = True
>>> if self.spam == None:
>>> self.spam = 0
>>> orderUpdated = True
>>> if orderUpdated:
>>> print('You can\'t order None, so I am updating your order')
However, if there are (lots) more than just 3 items on the menu the code for updateOrder would become very long and worse repetitive.
You have to use a loop and change the each value of the list during the loop
a=[1, 2, 3]
for i in range(len(a)):
a[i] += 1
Output will be
[2, 3, 4]
To access and change values in a list, you need to select items based on their location (you can also use slices). So, a[0] = 1, a[1] = 2 and so on. To change the value of a[0], you need to assign a new value to it (as done in the for loop).
Your example does not work because you are just changing the value of i (which is 1, then 2, then 3), instead of actually changing the list. You are not selecting any item from the list itself.
The documentation is given here (see section 3.1.3)
EDIT
Based on your clarification: Creating a list of variables that have been defined elsewhere:
a, b, c = 5, 6, 7
letters = [a, b, c]
# See id of variable a
id(a)
# 94619952681856
# See id of letters[0]
id(letters[0]
# 94619952681856
# Add 1 to letters[0]
letters[0] += 1
# See id of letters[0]
# 94619952681888
As you can see, when the list is first created, the item in the list points to the same variable However, as soon as the value in the list is changed, python creates a new item, so that the original value is unchanged.
This works the other way around also. Any change in the variable a will not affect the list, as once the variable is modified, its id will change, while the id of the item in the list will not.
And in the breakfast example, why don't you just assign 0 as the default value of each dish, instead of None? It would be a lot easier, unless there is some other reason for it.
EDIT 2:
If you need to update your attributes in the way that you have given, you would need to use the setattr method
class breakfast():
def __init__(self, eggs=None, bacon=None, spam=None):
self.eggs = eggs
self.bacon = bacon
self.spam = spam
# Create a list of attributes. This will return [self, eggs,bacon,spam]
attributes = list(locals().keys())
attributes.remove('self') # Remove self from the list
updateItems = []
for i in attributes:
# Check if the attribute is None or not
if getattr(self, i) == None:
updateItems.append(i)
else:
pass
for i in updateItems:
setattr(self, i, 0) # Set the attributes that are None to 0

Python for loop with ifs

What I have:
I have two keys in a dictionary:
one with values and
one with the index of the value.
d = {}
d['inds'] = [0, 5, 4, 2, 2, 5, 1]
d['vals'] = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]
What I want to do:
I want to loop through the dictionary and:
If the next iteration index = the last iteration index +1, to list the corresponding value
If the next iteration index does not = the last iteration index +1, print 0 and keep going. so basically just filling in 0 when there is a missing index
What I have tried
If I use the below loop:
for i in d['inds']:
for v in d['vals']:
for x in range(0, i):
if i == x+1:
print(v)
break
else:
print(0)
I get the list of values 6 times.
So I tried swapping i and x:
for i in d['inds']:
for v in d['vals']:
for x in range(0, i):
if x == i+1:
print(v)
break
else:
print(0)
Now I just get 0 listed 7 times.
TL;DR
How do I loop through a dictionary's values and indexes with a conditional statement, what am I doing wrong?
If I understand correctly, you want something like this:
for i in range(len(d['inds'])):
if i in d['inds']:
print(d['vals'][i])
else:
print(0)
This iterates through all the possible indices, prints 0 if the current index is not in d['inds'], and prints the value at the current index if it is.
This solution requires functions chain and defaultdict:
from itertools import chain
from collections import defaultdict
Create a new dictionary of lists:
G = defaultdict(list)
Populate it with the data from d:
for k,v in zip(d['inds'], d['vals']):
G[k].append(v)
#{0: [1.0], 5: [2.0, 6.0], 4: [3.0], 2: [4.0, 5.0], 1: [7.0]}
Create a range of indexes:
indexes = range(min(d['inds']), max(d['inds']) + 1)
Lookup each index in the new dictionary. If an index is not in the dictionary, use [0] as the value. The result is a nested list that can be flattened with chain:
list(chain.from_iterable(G.get(x, [0]) for x in indexes))
#[1.0, 7.0, 4.0, 5.0, 0, 3.0, 2.0, 6.0]

3Sum using python3 and enumarate

I want to solve the following task using 'enumerate' in python3
The way enumerate works is demonstrated below
nums=(2,7,1,15) # a tuple
for num in enumerate(nums):
print(num, 'hello')
#output
#(0, 2) hello #enumarate(nums) = (0,2)
#(1, 7) hello
#(2, 1) hello
#(3, 15) hello
for count, num in enumerate(nums):
print(num, 'hello')
# Output
#2 hello here count=0 but not displayed
#7 hello here count=1 but not displayed
#1 hello here count=2 but not displayed
#15 hello here count=3 but not displayed
Using the above principle, given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = target sum? Find all unique triplets in the array which gives the sum = target sum.
A solution set for target sum =10 is:
[
[0,1,2]
]
where num at 0th index+num at 1st index+num at 2nd index(7+2+1=10).
Do you have an idea for an algorithm to solve the problem?
I would probably do something like build up two dicts listing all the ways to use the array indexes make a sum with 1 number and 2 numbers to be a certain key value.
E.g., if I had been given nums = [2, 7, 1, 2, 3], I would write code to build up a table like:
one_sum = {1: [2],
2: [0, 3],
3: [4],
7: [1]}
I would use a defaultdict from collections module to efficiently write this code (initialized as one_sum = defaultdict(list) above, though a set would also be a valid data structure for the problem).
It would be straightforward to use enumerate for this part; e.g.,
for i, n in enumerate(nums):
one_sum[n].append(i)
Then I would then build up a two_sum table this time showing all pairs of indexes that make a certain sum. Continuing with the example above, I would want to generate:
two_sum = {3: [(0, 2), (2, 3)],
4: [(2, 4)],
5: [(0, 4), (3, 4)],
8: [(1, 2)],
9: [(0, 1), (1, 3)],
10: [(1, 4)]}
(Note one way to efficiently do this is to loop through the built up one_sum, but be careful not to re-use an index e.g., don't add (2,2) or (4,4) to two_sum[4] because while nums[2] + nums[2] does add up to 4, it uses an index twice (so isn't unique). Also be careful not to double add indexes that are out of order.)
Finally I would loop through the one_sum dict, looking at indices that sum to k and then look in two_sum to see if there are any pairs of indices that sum to target-k, and if so then join the pairs together (checking to sort indices and not repeat indices in a tuple) having found a solution.
For a target of 10 this would ideally build up
three_sum = [(0,1,2), (1,2,3)]
# Note both were added from combining one_sum[1] with two_sum[9]
# nothing from combining one_sum[2] with two_sum[8] as they reuse indexes
# nothing from combining one_sum[3] as two_sum[7]==[]
# nothing new from combining one_sum[7] with two_sum[3] as (0,1,2) and (1,2,3) already present.
Here's a brute force method. It's not as efficient as this algorithm can be, mind you.
def f(nums, target):
sols = []
for i1, n1 in enumerate(nums):
for i2, n2 in enumerate(nums[i1+1:]):
for i3, n3 in enumerate(nums[i2+1:]):
if (n1 + n2 + n3 == target):
sols.append([i1, i2, i3])
return sols

finding the keys of all the largest values in python dictionary?

if I have a dictionary
x ={0: 0, 1: 4, 2: 0, 3: 2, 4: 2, 5: 4}
how do i get the keys of all the largest values
In this case they would be 1 and 5 .
Not a duplicate question. looking to find all the keys and not just the one.
x ={0: 0, 1: 4, 2: 0, 3: 2, 4: 2, 5: 4}
maximum = max(x.values())
keys = [key for key, value in x.items() if value == maximum]
print(keys) # => [1, 5]
There is a class in collections called Counter that does exactly what you want. It provides the exact functionality you require via it's most_common method:
from collections import counter
maxes = Counter(x).most_common(2)
print([x[0] for x in maxes])
[1, 5]
Now this is probably not exactly what you want because I hard coded in the number 2. You can get this by using another Counter on the values of your dictionary!
x = Counter(x) # This preserves x: just makes it a subclass of dict
max_count = Counter(x.values())[x.most_common(1)[0][1]]
maxes = x.most_common(max_count)
maxes = [x[0] for x in maxes]
Here, I compute the number of times that the most common value occurs by counting all the different values, and then checking the maximum one using x.most_common(1)[0][1].
Please do not select this answer. #BrightOne has the right answer. This is just a thing I did to see if I could avoid using anything but Counters. It is not actually a good idea.

How to find the index of the largest numbers in a list

In a list, there might be several largest numbers. I want to get the indices of them all.
For example:
In the list a=[1,2,3,4,5,5,5]
The indices of the largest numbers are 4,5,6
I know the question is easy for most of people, but please be patient to answer my question.
Thanks :-)
In [156]: a=[1,2,3,4,5,5,5]
In [157]: m = max(a)
In [158]: [i for i,num in enumerate(a) if num==m]
Out[158]: [4, 5, 6]
1) create a variable maxNum = 0
2) loop through list if a[i] > maxNum : maxNum = a[i]
3)loop through list a second time now if a[i] == maxNum: print(i)
Try this:
a=[1,2,3,4,5,5,5]
b = max(a)
[x for x, y in enumerate(a) if y == b]
Use heapq:
import heapq
from operator import itemgetter
a=[1,2,3,4,5,5,5]
largest = heapq.nlargest(3, enumerate(a), key=itemgetter(1))
indices, _ = zip(*largest)
Of course, if your list is already sorted (your example list is), it may be as simple as doing
indices = range(len(a) - 3, len(a))
mylist=[1,2,3,3,3]
maxVal=max(mylist)
for i in range(0,len(mylist)):
if(mylist[i]==maxVal):
print i

Resources