Are there any shorter way for this way? - python

Lets say i have variables a,b,c,d,e,f.. every time 2 of the 6 variables will have value = 0 randomly. So my code is like this
if(a == 0 and b == 0):
run c,d,e,f
elif(a == 0 and c == 0):
run b,d,e,f
...
...
continue until end of all combination
So the coding will be very long, are there any other approach ?

You can put all numbers into a list and then feed a list comp of that list into the run function - ignoring elements that are 0:
def run(p1,p2,p3,p4):
print(p1,p2,p3,p4)
# 3 test cases
for d in [ [ 1,2,0,3,4,0], [0,0,2,3,4,1], [4,3,0,2,1,0]]:
run(*[x for x in d if x]) # *[1,2,3] makes python provide the elements as params
Output:
1 2 3 4
2 3 4 1
4 3 2 1
run( *[1,2,3]) is the same as run(1,2,3)
0 is Falsy - so *[x for x in d if x] for a d=[0,1,2,3,0] does only use non falsy values of x in d: *[1,2,3]
truth value testing
you can exchange the list comp run(*[x for x in d if x]) against a generator comp if you like run(*(x for x in d if x)) to avoid the list creation (not that it matters here ;) )
#Mehrdad Dowlatabadi raised an interesting side question - if any other of the params is 0 you get an error due to a mismatch between function parameters and provided parameters from the list comprehension - you can negate that by defining defaults:
def run(p1=0, p2=0, p3=0, p4=0):
print(p1,p2,p3,p4)
So if you feed [0,1,2,0,0,0] into it it will still run.

If you want to run a function with the variables that aren't set to 0 you can first make a list of elements that are'nt 0
elements = [element for element in a, b, c, d, e if element !=0]
then call the function with elements list as arguments
run(*elements)
As a one liner :
run(*[element for element in a, b, c, d, e if element !=0])

Make run take a list:
def run(lst):
...
then use the filter function:
run(filter(None, [a, b, c, d, e, f]))
filter(None, lst) removes all fals-y elements.

Related

Sorting a Python list of numbers without knowing their values, but only their relationships among each other

I have a list of numbers which I can't really know their real values. Let's say list = [a,b,c,d] . But I have information about how they relate to each other:
a > b
b > d
d > c
Therefore I can infer that list sorted in descending order is [ a, b, d, c].
Another more complicated example
relationships =
- g > b
- d > c > a
- d > g
- f > e > a
- f > e > d
In this case we have multiple possible answers
Result:
[ [f, e, d, c, a, g, b],
[f, e, d, g, c, a, b],
[f, e, d, g, c, b, a],
... ]
just to name a few
I want the function to return me exactly that: a list of all possible answers. The relationships is a list of lists, where each list representes the relationship of the sorting in descending order. For example relationships = [[a,b],[b,c]] tells me that "a > b" and "b > c" . The inner lists inside relationships don't have to be necessarily of the same size. In case of an invalid/impossible input the algorithm should thrown an error. For example:
relationships = [[a,b],[b,c],[c,a] is an impossible case
What's the best approach for this that is also efficient ? I was thinking about using graphs theory where the graphs cannot be acyclic. For example A -> B means Node A goes to B meaning A > B , therefore B -> A cannot exist. Somehow like a binary tree, but in this case instead of allowing 2 child per node we can only allow 1.
Is that a good idea to start on this or does anyone have any better idea on how to approach this?
You need 3 ideas to understand this.
First is topological sorting via Kahn's algorithm. See https://en.wikipedia.org/wiki/Topological_sorting#Kahn's_algorithm for a description. I am walking through all of the way to generate a topological sort by that algorithm, and yielding each one.
The second is stack based programming. Think Forth, or RPN. The idea is that I have a stack of actions. At each step I take the top action off of the todo list and do it. If I add items onto the todo list, then that is like having recursive calls. In my case the actions are to choose (try all choices that make sense), add (add an element to the sorted list and do bookkeeping), remove (remove an element from the sorted list and do bookkeeping) and try (schedule the actions add/choose/remove - but placed in the opposite order because stack).
The third is generators. I just yield multiple times and then continue from where I was. This can be looped over, turned into a list, etc.
Here is the code.
def topological_sorts (descending_chains):
arrive_to = {}
outstanding_arrivals = {}
for chain in descending_chains:
for x in chain:
if x not in arrive_to:
arrive_to[x] = set([])
outstanding_arrivals[x] = 0
for i in range(1, len(chain)):
arrive_to[chain[i-1]].add(chain[i])
for item in arrive_to:
for x in arrive_to[item]:
outstanding_arrivals[x] += 1
todo = [['choose', None]]
sorted_items = []
chosen = set([])
items = [x for x in arrive_to]
while len(todo):
action, item = todo.pop()
if action == 'choose':
choices = []
for x in outstanding_arrivals:
if x not in chosen and 0 == outstanding_arrivals[x]:
choices.append(x)
if 0 == len(choices):
if len(sorted_items) == len(items):
yield sorted_items
else:
print((choices, outstanding_arrivals, sorted_items))
break
else:
for item in choices:
todo.append(['try', item])
elif action == 'try':
chosen.add(item)
sorted_items.append(item)
todo.append(['remove', item])
todo.append(['choose', None])
todo.append(['add', item])
elif action == 'add':
chosen.add(item)
for x in arrive_to[item]:
outstanding_arrivals[x] -= 1
elif action == 'remove':
chosen.remove(item)
sorted_items.pop()
for x in arrive_to[item]:
outstanding_arrivals[x] += 1
else:
yield ('todo:', action, item)
and here is how to use it for your second example.
for sort in topological_sorts([
['g', 'b'],
['d', 'c', 'a'],
['d', 'g'],
['f', 'e', 'a'],
['f', 'e', 'd']]):
print(sort)
I wrote Python code for Topological sort on site Rosetta Code here.
The input is a dict mapping nodes to the set of nodes it depends on, (in your case, nodes they are "greater than"). use the following to represent your example dependencies:
a,b,c,d,e,f,g = 'abcdefg' # For ease of use
data = {c:a, d:'cag', e:'ad', f:'ead', g:b} # <node>:<is_greater_than>
dat = {key: set(val) for key, val in data.items()}
print ('\n'.join( toposort2(dat) ))
The correct output is the following, where nodes on the same line can appear in any order before nodes from other lines above it:
a b
c g
d
e
f
Note your solution you give to your example is wrong in that you cannot have f,e,d then followed immediately by b; it must by c or g (in any order); then a or b (in any order).

Complex behaviour with lists

I need to make some strange and complex calculation with lists. I have tried and I have endeavored to get it up and running, but it runs into error. better saying quite difficult to achieve that behavior.
I have following lists.
A = [1,1,1,2,2,2]
B = [3,3] # B list is length of numbers 1 and 2.
E = [10,10]
C = 1
D = []
I have this code, but not really working:
for k in B:
for j in E:
for i in range(len(A)-k):
print(i)
if i == 0:
D.append(C)
else:
D.append(C+(E[k]))
print(D)
Explaining to achieve results.
I want to have a for-loop, which enables to append values to my empty list, which looks at first 3 values in the beginning of list A by taking B[0]= 3, do something with first 3 values. And looks at B[1]= 3, ie. take the last 3 values in the list A, then do something to them and append them all in order to empty list.
First 3 values:
When A[0] is selected, I want to have D[0] = C, and in case A[1] and A[2], B list should be B[1]= C + 1*E[0] and B[2]= C + 2*E[0].
Last 3 values:
When A[3] is selected, I want to have D[3] = C, and in case A[4] and A[5], B list should be B[4]= C + 1*E[1] and B[5]= C + 2*E[1].
Expected output:
[1,11,21,1,11,21]
I want to get it programmatically, in case changing A list to A = [1,1,2,2] and B = [2,2] or something else.
Initialization of your lists
A = [1,1,1,2,2,2]
B = [3,3] # B list is length of numbers 1 and 2.
E = [10,10]
C = 1
D = []
we want to count in A starting the first time from 0, the next times from the previous start plus how many items we have used, hence we initialize start
start = 0
We start a loop on the elements b of B, counting them in k, we extract from A the elements we need and update the start position for the next pass
for k, b in enumerate(B):
sub_A = A[start:start+b]
start = start+b
Now an inner loop on the elements a of the sub-list, counting them with i, note that for the first item i is zero and so we append C+0*E[k]=C, as requested
for i, _ in enumerate(sub_A):
D.append(C+i*E[k])
To see everything without my comments
start = 0
for k, b in enumerate(B):
sub_A = A[start:start+b]
start = start+b
for i, _ in enumerate(sub_A):
D.append(C+i*E[k])

Iterating through functions using for loop

I currently have multiple functions as below:
vect_1 = CountVectorizer(parameters)
vect_2 = CountVectorizer(parameters)
vect_3 = CountVectorizer(parameters)
vect_3 = CountVectorizer(parameters)
which I am trying to iterate each one of them. I've tried:
for i in range(4):
vect = vect_[i]
print vect
And I am struggling to correctly defining 'vect' part as it just becomes a string. Any ideas please?
Thanks
This is the pythonic way to do it, using a list:
vects = [
CountVectorizer(parameters),
CountVectorizer(parameters),
CountVectorizer(parameters),
CountVectorizer(parameters)
]
for v in vects:
print(v)
Whenever you see that variable names are being generated dynamically from strings, that's a warning that you need a better data structure to represent your data. Like a list, or a dictionary.
Of course not this, but try globals (in def use locals):
for i in range(1,5):
vect = globals()['vect_%s'%i]
print(vect)
Although still the most pythonic way is using #Oscar's solution
You can just loop through all your parameters.
vectors = []
parameters = []
#Put code for adding parameters here
for parameter in parameters:
vectors.append(CountVectorizer(parameter))
This loops through the parameters you have set and runs the function with each parameter. You can now access all the outputs from the vectors list.
I prefer using list or dict
def func_a(a):
print(a)
def func_b(b):
print(b, b)
def func_c(c):
print(c, c, c)
def func_d(d):
print(d, d, d, d)
# use list
func_list = [func_a, func_b, func_c, func_d]
for i in range(4):
func_list[i](i)
# use dict
func_dict = {"vect_1": func_a,
"vect_2": func_b,
"vect_3": func_c,
"vect_4": func_d}
for i in range(1, 5):
func_dict["vect_" + str(i)](i)
which will print
0
1 1
2 2 2
3 3 3 3
1
2 2
3 3 3
4 4 4 4

How to compare 4 consecutive elements in a list?

I am new to coding so I apologize in advance if what I am asking is simple or doesn't make much sense but I will try to elaborate as much as I can. First of all this is not for any work or project I am simply studying to learn a bit of coding for my satisfaction. I've been trying to find some real life problems to apply into coding (pseudo code mostly but python language would also be kind of understandable to me).
I wanted to be able to have a list of x elements and compare 4 of them sequentially.
For example, myList = [a, b, c, d, e, f, g, h, i, j, k, l]
First I want to compare a,b,c and d.
If b>a, c>b, d>c and d> all of 3 previous ones (d>a, d>b, d>c) I want to do something otherwise go to next comparison.
Then I wanted to compare b,c,d and e.
Similarly if c>b, d>c, e>d and e> all of 3 previous ones (e>b, e>c, e>d) I want to do something otherwise go to next comparison.
What if my list contains infinite elements? myList = [:]
Where do I start? Do I have to have a starting point?
I am guessing I have to use a for loop to iterate through the list but I honestly can't figure out how to iterate through the first 4 elements and then continue from the second element in 4 element batches.
Since I am currently studying the Arrays and lists maybe there is some functionality I am missing? Or I simply my brain can grasp it.
I tried looking at other posts in stackoverflow but honestly I can't figure it out from other people's answers. I would appreciate any help or guidance.
Thanks in advance.
You can use the built-in all() function for this problem:
myList = [5, 4, 3, 6, 3, 5, 6, 2, 3, 10, 11, 3]
def do_somthing():
#your code here
pass
for i in range(len(myList)-4):
new_list = myList[i:i+4] #here, using list slicing to jump ahead four elements.
if all(new_list[-1] > b for b in new_list[:-1]) and all(new_list[:-1][c] > new_list[:-1][c+1] for c in range(len(new_list)-2)):
do_something()
L = [...]
# get all the valid indices of the elements in the list, except for the last 4. These are the indices at which the 4-element windows start
for i in range(len(L)-4):
window = L[i:i+4] # the 4 elements you want to compare
print("I am considering the elements starting at index", i, ". They are:", window)
a,b,c,d = window
if d>a>b>c<d and d>b:
print("The checks pass!")
Now, there is a simpler way to do this:
for a,b,c,d in (L[i:i+4] for i in range(len(L)-4):
if d>a>b>c<d and d>b:
print("The checks pass!")
to consume just one item at a time from an iterator and operate on 4 lagged elements try a circle buffer:
# make a generator as example of 'infinte list'
import string
agen = (e for e in string.ascii_lowercase)
# initialize len 4 circle buffer
cb = [next(agen) for _ in range(4)] # assumes there are at least 4 items
ptr = 0 # initialize circle buffer pointer
while True:
a,b,c,d = (cb[(i+ptr)%4] for i in range(4)) # get current 4 saved items
# some fuction here
print(a,b,c,d)
# get next item from generator, catch StopIteration on empty
try:
cb[ptr] = next(agen)
except StopIteration:
break
ptr = (ptr + 1)%4 # update circle buffer pointer
a b c d
b c d e
c d e f
d e f g
e f g h
f g h i
g h i j
h i j k
i j k l
j k l m
k l m n
l m n o
m n o p
n o p q
o p q r
p q r s
q r s t
r s t u
s t u v
t u v w
u v w x
v w x y
w x y z
'some function' could include a stopping condition too:
# random.choice() as example of 'infinte iterator'
import string
import random
random.choice(string.ascii_lowercase)
# initialize len 4 circle buffer
cb = [random.choice(string.ascii_lowercase) for _ in range(4)] # assumes there are at least 4 items
ptr = 0 # initialize circile buffer pointer
while True:
a,b,c,d = (cb[(i+ptr)%4] for i in range(4)) # get current 4 saved items
# some fuction here
print(a,b,c,d)
if a<b<c<d: # stopping condition
print("found ordered string: ", a,b,c,d)
break
# get next item from generator, catch StopIteration on empty
try:
cb[ptr] = random.choice(string.ascii_lowercase)
except StopIteration:
break
ptr = (ptr + 1)%4 # update circle buffer pointer
o s w q
s w q k
w q k j
q k j r
k j r q
j r q r
r q r u
q r u v
found ordered string: q r u v
Since you can index a list, how about start from index 0, compare the 0th, (0+1)th, (0+2)th, and (0+3)th elements. Then, by the next round, increase your index to 1, and compare the 1st, (1+1)th, (1+2)th, and (1+3)th elements, and so on. For the nth round, you compare the n, n+1, n+2, and (n+3)th elements, until you reach the 4th element before the end. This is how you generally do stuff like 'testing m elements each time from a sequence of length n', and you can easily expand this pattern to matrices or 3d arrays. The code you see in other answers are basically all doing this, and certain features in Python make this job very easy.
Now, 'what if the list contains infinite elements'? Well, then you'll need a generator, which is a bit advanced at this stage I assume, but the concept is very simple: you let a function read that infinite stream of elements in a (might be infinite) loop, set a cursor on one of them, return (yield) the element under the cursor as well as the 3 elements following it each time, and increase the cursor by one before the next loop starts:
def unsc_infinity(somelist):
cur = 0
while True:
yield somelist[c:c+4]
cur = cur + 1
infinity_reader = unsc_infinity(endless_stream)
next(infinity_reader)
# gives the 0, 1, 2, 3 th elements in endless_stream
next(infinity_reader)
# gives the 1, 2, 3, 4 th elements in endless_stream
next(infinity_reader)
# ...
And you can loop over that generator too:
for a, b, c, d in unsc_infinity(endless_stream):
if d>a>b>c<d and d>b:
do_something()
Hope that helps a bit for you to build a mental model about how this kind of problems are done.

Mapping two list of lists based on its items into list pairs in Python

I have two list of lists which basically need to be mapped to each other based on their matching items (list). The output is a list of pairs that were mapped. When the list to be mapped is of length one, we can look for direct matches in the other list. The problem arises, when the list to be mapped is of length > 1 where I need to find, if the list in A is a subset of B.
Input:
A = [['point'], ['point', 'floating']]
B = [['floating', 'undefined', 'point'], ['point']]
My failed Code:
C = []
for a in A:
for b in B:
if a == b:
C.append([a, b])
else:
if set(a).intersection(b):
C.append([a, b])
print C
Expected Output:
C = [
[['point'], ['point']],
[['point', 'floating'], ['floating', 'undefined', 'point']]
]
Just add a length condition to the elif statement:
import pprint
A = [['point'], ['point', 'floating']]
B = [['floating', 'undefined', 'point'], ['point']]
C = []
for a in A:
for b in B:
if a==b:
C.append([a,b])
elif all (len(x)>=2 for x in [a,b]) and not set(a).isdisjoint(b):
C.append([a,b])
pprint.pprint(C)
output:
[[['point'], ['point']],
[['point', 'floating'], ['floating', 'undefined', 'point']]]
Just for interests sake, here's a "one line" implementation using itertools.ifilter.
from itertools import ifilter
C = list(ifilter(
lambda x: x[0] == x[1] if len(x[0]) == 1 else set(x[0]).issubset(x[1]),
([a,b] for a in A for b in B)
))
EDIT:
Having reading the most recent comments on the question, I think I may have misinterpreted what exactly is considered to be a match. In which case, something like this may be more appropriate.
C = list(ifilter(
lambda x: x[0] == x[1] if len(x[0])<2 or len(x[1])<2 else set(x[0]).intersection(x[1]),
([a,b] for a in A for b in B)
))
Either way, the basic concept is the same. Just change the condition in the lamba to match exactly what you want to match.

Categories

Resources