I have a list of expr with a different number of variables as follows:
G = [[-x_1 + y_1], [-x_2 + y_1 + y_2], [y_1 + y_2] , [-y_3] , ....]
I want to evaluate these expressions using sympy and lambdify. For this purpose, I have written the following instructions:
def f(item):
return lamndify(list(tem.free_symbols), item)
for item in G:
f_ = f(item)
...
Now, what should I do to call f_ because there are different variables in each term?
Get the pertinent free_symbols, too. Perhaps make your function return those for you or else recapture them:
def f(item):
return lambdify(list(item.free_symbols), item)
def f2(item):
args = list(item.free_symbols)
return args, lambdify(args, item)
for [gi] in G:
args = list(gi.free_symbols)
f_ = f(gi)
a, f2_ = f2(gi)
assert f_(*args) == f2_(*a)
If you have a set of values you want to use like vals = {x_1:1,x_2:2,y_1:3,y_2:4,y_3:5} then something like this could be used:
>>> for [gi] in G:
... a, f2_ = f2(gi)
... v = [vals[i] for i in a]
... print(v, f2_(*v))
...
[3, 1] 2
[3, 2, 4] 5
[3, 4] 7
[5] -5
Related
I have a list:
ll = [1,2,3]
I have a function:
def hello(x, v):
x[v] = True
return x
I have an iterable ii = [1,2]
Currently, I do:
for i in ii:
ll = hello(x=ll, v=i)
How to do this with reduce and partial?
EDIT:
I solved it with:
reduce(lambda x,y: hello(x,y), ii, ll)
While iterating over an iterator I would like to avoid the ultimate item and stop at the penultimate item - how do I do this?
from itertools import product
from collections import namedtuple
param_list = []
Parameter = namedtuple("Parameter", ['bad', 'good'])
param1 = Parameter(["peanut", "gluten"], ["bacon", "pickle"])
param_list.append(param1)
param2 = Parameter([0], [1, 22])
param_list.append(param2)
param3 = Parameter([0, 1], [2, 3, 4, 9])
param_list.append(param3)
param4 = Parameter(["football"], ["running", "yoga"])
param_list.append(param4)
for prod in product(*param_list): # -- I want to skip the last product --
for sub_prod in product(*prod):
prod = [str(x) if type(x) is not str else x for x in sub_prod]
print ", ".join(prod)
Note -
param_list is a variable length list.
If it were a list instead of an iterator, I would have used for prod in product_list[:-1] :
The print statement is for illustration only.
To avoid using the last item (but not avoid pulling the last item, which is impossible in general), you could do something like this:
def skip_last(seq):
it = iter(seq)
p = next(it)
for n in it:
yield p
p = n
>>> print (''.join(skip_last('ABCDE')))
'ABCD'
This is a generator that will iterate through a sequence and yield every item except the last one.
Using the pairwise recipe mentioned in the itertools documentation:
from itertools import tee, izip, imap
from operator import itemgetter
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return izip(a, b)
you can define
def init(iterable):
return imap(itemgetter(0), pairwise(iterable))
This gets you
>>> list(init(x for x in [1,2,3,4,5]))
[1, 2, 3, 4]
Based off #khelwood's answer -
from itertools import product
from collections import namedtuple
param_list = []
Parameter = namedtuple("Parameter", ['bad', 'good'])
param1 = Parameter(["peanut", "gluten"], ["bacon", "pickle"])
param_list.append(param1)
param2 = Parameter([0], [1, 22])
param_list.append(param2)
param3 = Parameter([0, 1], [2, 3, 4, 9])
param_list.append(param3)
param4 = Parameter(["football"], ["running", "yoga"])
param_list.append(param4)
# Pulling one item ahead of loop so as to avoid the last item.
iterable = product(*param_list)
prev_prod = next(iterable)
for prod in iterable:
for sub_prod in product(*prev_prod): # Using 'prev_prod' instead of 'prod'
prod_str = [str(x) if type(x) is not str else x for x in sub_prod]
print ", ".join(prod_str)
prev_prod = prod
In the code below, I create identifiers a and b that point to two separate lists with the same value, verified by their unique id values.
Then I insert both into a list, and try to find the index for b, but instead it finds the index for a.
In [21]: a = [3,2]
In [22]: b = [3,2]
In [23]: id(a)
Out[23]: 4368404136
In [24]: id(b)
Out[24]: 4368429352
In [25]: c = [[4,3], a, [5,7], b, [6,3]]
In [26]: c.index(a)
Out[26]: 1
In [27]: c.index(b)
Out[27]: 1
How can I return 3? A while loop would work but it seems like there should be a function for this.
i = 0
match = False
while (not match) and (i < len(c)):
if id(c[i]) == id(b):
print i
match = True
i += 1
list.index() matches values by equality, not identity.
It is easy enough to write a helper function that uses a loop, testing with the is operator and the enumerate() function:
def index_by_identity(lst, target):
for i, obj in enumerate(lst):
if obj is target:
return i
# no object matches
raise IndexError(target)
or, alternatively with the next() function and a generator expression:
def index_by_identity(lst, target):
try:
return next(i for i, obj in enumerate(lst) if obj is target)
except StopIteration:
# no object matches
raise IndexError(target)
Demo:
>>> a = [3, 2]
>>> b = [3, 2]
>>> a is b
False
>>> c = [[4, 3], a, [5, 7], b, [6, 3]]
>>> def index_by_identity(lst, target):
... for i, obj in enumerate(lst):
... if obj is target:
... return i
... # no object matches
... raise IndexError(target)
...
>>> index_by_identity(c, b)
3
>>> def index_by_identity(lst, target):
... try:
... return next(i for i, obj in enumerate(lst) if obj is target)
... except StopIteration:
... # no object matches
... raise IndexError(target)
...
>>> index_by_identity(c, b)
3
I am new to Python, and am trying to create a function which creates lists with different material parameters from user inputs as shown in the code below.
def material():
layers = int(raw_input("State the number of material layers in the wall (0 for default material): "))
rho = [] # Density [kg/m3]
c = [] # Heat capacity [J/(kg K)]
k = [] # Heat conductivity [W/(m K)]
#a = [] # Thermal diffusivity [m2/s]
d = [] # Thickness of material [m]
# Saveing material properties
if layers == 0:
rho.append(2300)
c.append(900)
k.append(1.6)
d.append(3.2)
layers = 1
else:
for i in range(layers):
print "\n" "Define thermal properties for material", i+1,"(starting from left)"
rho.append(float(raw_input("Density [kg/m3]: ")))
c.append(float(raw_input("Heat capacity [J/(kg K)]: ")))
k.append(float(raw_input("Heat conductivity [W/(m K)]: ")))
d.append(float(raw_input("Thickness [m]: ")))
return ???
How should I return rho, c, k, d and layers so I am able to e.g. print – or use the value of – e.g. the second item in the list of d?
print d[1]
How should I return rho, c, k, d and layers [...] ?
Simply do it:
return rho, c, k, d, layers
And then you'd call it like
rho, c, k, d, layers = material()
print d[1]
Note that the more stuff you're returning, the more likely it is you're going to want to wrap it all together into some structure like a dict (or namedtuple, or class, etc.)
return can return multiple values if you separate them with commas:
return rho, c, k, d, layers
This will make material return a tuple containing rho, c, k, d, and layers.
Once this is done, you can access the values returned by material through unpacking:
rho, c, k, d, layers = material()
Here is a demonstration:
>>> def func():
... return [1, 2], [3, 4], [5, 6]
...
>>> a, b, c = func()
>>> a
[1, 2]
>>> b
[3, 4]
>>> c
[5, 6]
>>> a[1]
2
>>>
def return_values():
# your code
return list1, list2
and get the value like below
value1, value2 = return_values()
def function_returning_multiple_list():
l1=[]
l2=[]
l3=[]
return (l1,l2,l3)
def another_fucntion():
list1,list2,list3=function_returning_multiple_list()
print list2
I have a few arrays containing integer and strings. For example:
myarray1 = [1,2,3,"ab","cd",4]
myarray2 = [1,"a",2,3,"bc","cd","e",4]
I'm trying to combine only the strings in an array that are next to each other. So I want the result to be:
newarray1= [1,2,3,"abcd",4]
newarray2= [1,"a",2,3,"bccde",4]
Does anyone know how to do this? Thank you!
The groupby breaks the list up into runs of strings and runs of integers. The ternary operation joins the groups of strings and puts them into a temporary sequence. The chain re-joins the strings and the runs of integers.
from itertools import groupby, chain
def joinstrings(iterable):
return list(chain.from_iterable(
(''.join(group),) if key else group
for key, group in
groupby(iterable, key=lambda elem: isinstance(elem, basestring))))
>>> myarray1 = [1,2,3,"ab","cd",4]
>>> newarray1 = [myarray1[0]]
>>> for item in myarray1[1:]:
... if isinstance(item, str) and isinstance(newarray1[-1], str):
... newarray1[-1] = newarray1[-1] + item
... else:
... newarray1.append(item)
>>> newarray1
[1, 2, 3, 'abcd', 4]
reduce(lambda x, (tp, it): tp and x + ["".join(it)] or x+list(it), itertools.groupby( myarray1, lambda x: isinstance(x, basestring) ), [])
a = [1,2,3,"ab","cd",4]
b = [1,a,2,3,"bc","cd","e",4]
def func(a):
ret = []
s = ""
for x in a:
if isinstance(x, basestring):
s = s + x
else:
if s:
ret.append(s)
s = ""
ret.append(x)
return ret
print func(a)
print func(b)