I have a list:
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
There are multiple if usages that check a number is in the a list.
while True:
if 3 in a:
some_work1 #(different)
if 4 in a:
some_work2 #(different)
if 8 in a:
some_work3 #(different)
if 11 in a:
some_work4 #(different)
if 12 in a:
some_work5 #(different)
Are there any faster (less cpu usage) methods for these multiple if usages? (List a is always same. Also it does not change over iterations.). There is no dublicated items in the a list. Works do not overlap.
Python 3.8.7
Use a set which has constant insert and retrieve times. In comparison, the in operator performs a linear search in your a every check.
I'm not exactly sure what your use-case is without seeing your larger code. I'm assuming your use-case treats a as a list of flags. As such, a set fits the bill.
a = [1, 2, 3, 4, 5, 6, 7, 8, 9 10, 11, 12]
a = set(a) # pass an iterable
# or simply
a = {1, 2, 3, 4, 5, 6, 7, 8, 9 10, 11, 12}
# or built at runtime
a = set()
a.add(1)
a.add(2)
if 3 in a:
some_work1
If you want a more efficient switch statement, you have already found it. Python uses if..elif for this. This ensures each is evaluated in sequence with short-circuit. If you could match multiple outcomes, use a dict (e.g. {3: functor3, 4: functor4, ...}. A functor is a callable, ie it has a __call__() method defined. A lambda also satisfies this.
A set is an unordered collection that does not allow duplicates. It's like a dictionary but with the values removed, leaving just keys. As you know, dictionary keys are unique, and likewise members of a set are unique. Here we just want a set for performance.
option 1
You could use a dictionary whose keys are the number in a and values the corresponding function. Then you loop over them once and store the needed functions in an array (to_call). In the while loop you simply iterate over this array and call its members.
def some_work1():
print("work1")
def some_work2():
print("work2");
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
func = {3:some_work1,4:some_work2}
to_call = []
for k in func:
if k in a:
to_call.append(func[k])
while 1:
for f in to_call:
f();
Option 2
Write some kind of code generator that reads a and generates a .py file containing the function calls.
Related
This question already has answers here:
Finding and replacing elements in a list
(10 answers)
Closed 2 years ago.
Is there a fancy method for replacing a specific value of a list with another value?
Like a shortcut for this:
>>> l = list(range(10))
>>> replacing = 3
>>> l[l.index(replacing)] = 4
>>> l
[0, 1, 2, 4, 4, 5, 6, 7, 8, 9]
With the example I gave it's easy enough to do via the [l.index()], but when the list reference is a few dots away it starts getting ugly.
It would be so much prettier to do something like this:
>>> some.thing.very.far.away.list = list(range(10))
>>> some.thing.very.far.away.list.replace(3, 4)
Edit:
I forgot to say why.
I want to edit the same list, and only edit one of the values.
I'm actually kind of supprized that lists doesn't have a built-in method like list.replace(old, new[, max), considering that strings do and it seems like python has built-ins for just about everying.
Build a new list with a list comprehension:
new_items = [4 if x==3 else x for x in l]
You can modify the original list in-place if you want, but it doesn't actually save time:
items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for index, item in enumerate(items):
if (item ==3 2):
items[index] = 4
you can assign "some.thing.very.far.away.list" to a temporary variable and apply replace function
some.thing.very.far.away.list = temp
something.very.far.away.list = temp.replace(x,y)
This can be a trick:
First define a dictionary with values you want to replace, than use a list comprehension using dictionary get with a default value.
You are passing el both as a key of the dictionary and as default value. If the key is found the corresponding value will be replaced otherwise the default value itself.
>>> l = [0, 1, 2, 4, 4, 5, 6, 7, 8, 9]
>>> rpl = {1: 23, 6: 12}
>>> [rpl.get(el, el) for el in l]
[0, 23, 2, 4, 4, 5, 12, 7, 8, 9]
You can use map method to iterate and replace certain value.
syntax : map(function, iterable, ...)
The returned value from map() (map object) can then be passed to functions like list() (to create a list), set() (to create a set) and so on.
l = list(range(10))
replacing = 3
l = list(map(lambda x: 4 if x == replacing else x, l)) # iterating over list l and replacing certain value using map method and converting map object in to another list.
print(l)
output = [0, 1, 2, 4, 4, 5, 6, 7, 8, 9]
it takes two parameter function and iterable. map() passes each item of the iterable to this function.
where lambda function takes argument x from sequence (l), assign 4 if x is equal to 4 .
to know more about map method Python map()
I need to write a function printMultiples(lst) that takes a list of numbers and PRINTS the number if it is a multiple of 8
>>> printMultiples([2, 3, 4, 5, 6, 7, 8, 9])
So whenever I run this I don't get any output just a blank line. I'm told I need to call the function printMultiples, but I am clueless how to do that.
printMultiples = [(2, 3 ,4, 5, 6, 7, 8, 9)]
def printMultiples(lst):
for i in lst[0]:
if (i%8==0):
print (i)
I should see the number 8 print out but I seem to be missing a step or a line.
The function is well defined, and it does what you want it to do. The problem is that you are naming a variable with the same name as your function, so it gets overriden, use the following:
multiples = [(2, 3 ,4, 5, 6, 7, 8, 9)]
def printMultiples(lst):
for i in lst[0]:
if (i%8==0):
print (i)
printMultiples(multiples)
Output:
8
As #roganjosh has suggested, you can improve your code by following PEP-8:
multiples = [(2, 3 ,4, 5, 6, 7, 8, 9)]
def print_multiples(lst):
for number in lst[0]:
if number % 8 == 0:
print(number)
print_multiples(multiples)
Your first line of code shows how to call the function:
>>> printMultiples([2, 3, 4, 5, 6, 7, 8, 9])
Node that the >>> signals that you can anything following it in the Python REPL. If you are saving this in a file, you don't need to type the >>>.
The problem with the rest of the code is that you assign a list to the same name that you give to your function. If you want to put the list in a variable, you should give it a different name:
multiples = [2, 3 ,4, 5, 6, 7, 8, 9]
Note that I also removed the parentheses. When you call the function by directly passing the array in, you need parentheses () around the brackets []. But when you assign a list to a variable, you don't need the parentheses at all.
Now to call the function with this variable, you put the variable name in parentheses after the function name:
printMultiples(multiples)
Add this line at the end of your program. Be sure that it is not indented.
Others have stated that your list containing the multiples cannot be the same name as your function. Also, why not just store the multiples as list, like this:
lst = [2, 3 ,4, 5, 6, 7, 8, 9]
def printMultiples(lst):
for i in lst:
if i%8==0:
print(i)
printMultiples(lst)
I have a set of related integers which I need to search for across a huge number of data, and am wondering what's considered to be the most Pythonic or efficient method for going about this.
For example, if I have a list of integers:
query = [1,5,7,8]
And need to find all objects that contain these values:
record_1 = [0,5,7,8,10,11,12]
record_2 = [1,3,5,8,10,13,14]
record_3 = [1,4,5,6,7,8,11]
record_4 = [1,5,6,7,8,10,14]
record_5 = [1,5,8,9,11,13,16]
I know it wouldn't be too difficult to load each record into a larger list and iteratively test each for whether or not they contain all the integers found in the query, but I am wondering if there's a more Pythonic way of doing it, or if there's a more efficient method than testing every value (which will become expensive when scaling).
Thanks in advance!
If the numbers in queries and records are unique I would represent them a sets (or frozensets for better performance). Lets assume you have a list of records and a query:
The filter function is applied onto the list of records. For each record the lambda function is executed to see if it is true. The lambda function checks if query is a subset of the current record. Thus the filtered list contains our results. The result is converted to a list.
query = set([1,5,7,8])
records = [
set([0,5,7,8,10,11,12]),
set([1,3,5,8,10,13,14]),
set([1,4,5,6,7,8,11]),
set([1,5,6,7,8,10,14]),
set([1,5,8,9,11,13,16]),
]
matches = list(filter(lambda r: query.issubset(r), records))
print(matches)
Output:
[{1, 4, 5, 6, 7, 8, 11}, {1, 5, 6, 7, 8, 10, 14}]
Using list map with issubset
for y,x in zip(records,map(lambda x : query.issubset(x),records)):
if x :
print(y)
{1, 4, 5, 6, 7, 8, 11}
{1, 5, 6, 7, 8, 10, 14}
I have recently created a GUI, which contents tables. User can insert values in cells. As shown figur below.
I want to use values to make some calculation based on values given by user. Rows can be added and removed based on choice of user. with other word, the data I get from user could come from just one row or several rows.
I manage to obtain all values from tables automatically and assign them to python list. Each row gives 5 elements in the list.
I have achieved that. Data in python list have to be processed and organised. This is exactly I want to have help. Because few dags I have been thinking, and I can not figure out, how to continue...
Python data as list from table. as an example.
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, '', 11, 12, 13, 14]
What I want to achieve!
I want to split list into 3 times len(data).
I have also achieved this.
def split_seq(seq, num_pieces):
start = 0
for i in range(num_pieces):
stop = start + len(seq[i::num_pieces])
yield seq[start:stop]
start = stop
for data in split_seq(data, int(len(data)/5)):
print(data)
Output would be:
[1, 2, 3, 4, 5]
[6, 7, 8, 9, 10]
['', 11, 12, 13, 14]
The difficulty part starts here.
I want to take each splitted list and throw them into an if condition and store values as variables and message those values to an external function.
Something like this below:
for i in range(len(splitted_list1)):
if splitted_list1[0] == '':
do nothing
else:
x_+str(i)= splitted_list1[i]
externalfunc(x_1,x_2,x_3,x_4,x_5)
for i in range(len(splitted_list2)):
if splitted_list2[0] == '':
do nothing
else:
x_+str(i)= splitted_list2[i]
externalfunc(x_1,x_2,x_3,x_4,x_5)
continues depending on number of splitted_lists
..............
I appreciate any help and you are welcome to come with another idea to come around this.
Use one single list and pass that to externalfunc.
The line x_+str(i)= ... is going to be interpreted as x_"0"= ... or whatever number eventually. The function is going to take in a possibly unknown number of variables. You can just group each "variable" into one list and index them based on the number instead. Which you already have. Each one would be in splitted_list0, splitted_list1, etc.
However, you do not need to asynchronously return the different lists. Instead, you can split the lists and put them in one larger list. This is a two-dimensional array. Seems scary but it's just some lists inside another list.
Now to pass each number to the externalfunc you can use each split list and pass it as an argument. Basically resulting in externalfunc(splitted_list0) and so on.
The final code ends up something like the following:
# Split the data into seperate lists:
split_lists = [data[i*(len(data)/3):(i+1)*(len(data)/3)] for i in range(3)]
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, '', 11, 12, 13, 14] becomes
# [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], ['', 11, 12, 13, 14]]
# Pass each list to the external function:
for i in range(split_lists):
externalfunc(split_lists[i])
# split_lists[i] will be [1, 2, 3, 4, 5] or [6, 7, 8, 9, 10], etc.
Note that the 3 in the first line of code can be changed to be any number smaller than the length of the list data. This is just the number of lists to split the data into. Remember to change every 3 if it's hardcoded or just add a variable. Finally, the function externalfunc will have the list of 5 numbers as the first and only argument of the function.
def externalfunc(nums):
for n in nums:
# n = each number in the list
# do something with n, write it somewhere, store it, print it.
print(n)
In python, set() is an unordered collection with no duplicate elements. However, I am not able to understand how it generates the output.
For example, consider the following:
>>> x = [1, 1, 2, 2, 2, 2, 2, 3, 3]
>>> set(x)
set([1, 2, 3])
>>> y = [1, 1, 6, 6, 6, 6, 6, 8, 8]
>>> set(y)
set([8, 1, 6])
>>> z = [1, 1, 6, 6, 6, 6, 6, 7, 7]
>>> set(z)
set([1, 6, 7])
Shouldn't the output of set(y) be: set([1, 6, 8])? I tried the above two in Python 2.6.
Sets are unordered, as you say. Even though one way to implement sets is using a tree, they can also be implemented using a hash table (meaning getting the keys in sorted order may not be that trivial).
If you'd like to sort them, you can simply perform:
sorted(set(y))
which will produce a sorted list containing the set's elements. (Not a set. Again, sets are unordered.)
Otherwise, the only thing guaranteed by set is that it makes the elements unique (nothing will be there more than once).
Hope this helps!
As an unordered collection type, set([8, 1, 6]) is equivalent to set([1, 6, 8]).
While it might be nicer to display the set contents in sorted order, that would make the repr() call more expensive.
Internally, the set type is implemented using a hash table: a hash function is used to separate items into a number of buckets to reduce the number of equality operations needed to check if an item is part of the set.
To produce the repr() output it just outputs the items from each bucket in turn, which is unlikely to be the sorted order.
As +Volatility and yourself pointed out, sets are unordered. If you need the elements to be in order, just call sorted on the set:
>>> y = [1, 1, 6, 6, 6, 6, 6, 8, 8]
>>> sorted(set(y))
[1, 6, 8]
Python's sets (and dictionaries) will iterate and print out in some order, but exactly what that order will be is arbitrary, and not guaranteed to remain the same after additions and removals.
Here's an example of a set changing order after a lot of values are added and then removed:
>>> s = set([1,6,8])
>>> print(s)
{8, 1, 6}
>>> s.update(range(10,100000))
>>> for v in range(10, 100000):
s.remove(v)
>>> print(s)
{1, 6, 8}
This is implementation dependent though, and so you should not rely upon it.
After reading the other answers, I still had trouble understanding why the set comes out un-ordered.
Mentioned this to my partner and he came up with this metaphor: take marbles. You put them in a tube a tad wider than marble width : you have a list. A set, however, is a bag. Even though you feed the marbles one-by-one into the bag; when you pour them from a bag back into the tube, they will not be in the same order (because they got all mixed up in a bag).