Transform a list of lists into another format - python

I have a list of lists that looks like this:
names_list = [
["first='Katie'", "last='Beckett'"],
["first='David'", "last='Seal'"],
["first='Eric'", "last='Swartz'"]
]
I want to transform it into this format:
object.filter(first='Katie', last="Beckett') | object.filter(first='David', last='Seal' | object.filter(first='Eric', last="Swartz')
This is what I've been trying:
def convert(list):
for i in list:
return reduce(lambda x,y: objects.filter + '(' + x + ', ' + y + ')' , i)
map(lambda i: convert(i), names_list ))

The "programming by accident" approach (ie trying anything aphazardly without the slightest understanding and hoping it will magically "kind of work") won't take you very far. You need to understand what you're doing and why.
First point: your target is a Python expression, not data, so what you want is not to "transform" your source data "into another format" but to dynamically build (and eval) the expression from your source data.
Second point: your source data format is just plain wrong, you don't want litteral "first=<...>" strings here but very obviously a list of dicts ie:
names_list = [
{"first":'Katie', "last":'Beckett'},
{"first":'David', "last":'Seal'},
{"first":'Eric', "last":'Swartz'}
]
This allow you to use dict unpacking in a function call, ie:
target = names_list[0]
result = object.filter(**target)
Third point: objects.filter + '(' + x + ', ' + y + ')' doesn't mean anything - trying to add a function and a string just won't work. Don't try to build Python expressions as string anyway, Python is expressive and dynamic enough to let you solve those kind of problems without such dirty hacks.
What you want here is to 1. build a sequence of calls (well results of the calls that is) to object.filter() then 2. "or" these results together.
The first step is quite easy:
items = [object.filter(**target) for target in names_list]
The second step is to "reduce" this sequence using the "biwise or" operator (|). reduce() is indeed the right function for this, you just need a function taking two of your items and "or'ing" them. The naive approach is to use a lambda:
result = reduce(lambda y, x: x | y, items)
but this is a case of reinventing the wheel since Python's operators (well, most of them) exist in a function version in the operator module:
import operator
result = reduce(operator.or_, items)

Related

looping over optional arguments (strings) in python

I have lists of strings, some are hashtags - like #rabbitsarecool others are short pieces of prose like "My rabbits name is fred."
I have written a program to seperate them:
def seperate_hashtags_from_prose(*strs):
props = []
hashtags = []
for x in strs:
if x[0]=="#" and x.find(' ')==-1:
hashtags += x
else:
prose += x
return hashtags, prose
seperate_hashtags_from_prose(["I like cats","#cats","Rabbits are the best","#Rabbits"])
This program does not work. in the above example when i debug it, it tells me that on the first loop:
x=["I like cats","#cats","Rabbits are the best",#Rabbits].
Thisis not what I would have expected - my intuition is that something about the way the loop over optional arguments is constructed is causing an error- but i can't see why.
There are several issues.
The most obvious is switching between props and prose. The code you posted does not run.
As others have commented, if you use the * in the function call, you should not make the call with a list. You could use seperate_hashtags_from_prose("I like cats","#cats","Rabbits are the best","#Rabbits") instead.
The line hashtags += x does not do what you think it does. When you use + as an operator on iterables (such as list and string) it will concatenate them. You probably meant hashtags.append(x) instead.

Python substitute elements inside a list

I have the following code that is filtering and printing a list. The final output is json that is in the form of name.example.com. I want to substitute that with name.sub.example.com but I'm having a hard time actually doing that. filterIP is a working bit of code that removes elements entirely and I have been trying to re-use that bit to also modify elements, it doesn't have to be handled this way.
def filterIP(fullList):
regexIP = re.compile(r'\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}$')
return filter(lambda i: not regexIP.search(i), fullList)
def filterSub(fullList2):
regexSub = re.compile(r'example\.com, sub.example.com')
return filter(lambda i: regexSub.search(i), fullList2)
groups = {key : filterSub(filterIP(list(set(items)))) for (key, items) in groups.iteritems() }
print(self.json_format_dict(groups, pretty=True))
This is what I get without filterSub
"type_1": [
"server1.example.com",
"server2.example.com"
],
This is what I get with filterSub
"type_1": [],
This is what I'm trying to get
"type_1": [
"server1.sub.example.com",
"server2.sub.example.com"
],
The statement:
regexSub = re.compile(r'example\.com, sub.example.com')
doesn't do what you think it does. It creates a compiled regular expression that matches the string "example.com" followed by a comma, a space, the string "sub", an arbitrary character, the string "example", an arbitrary character, and the string "com". It does not create any sort of substitution.
Instead, you want to write something like this, using the re.sub function to perform the substitution and using map to apply it:
def filterSub(fullList2):
regexSub = re.compile(r'example\.com')
return map(lambda i: re.sub(regexSub, "sub.example.com", i),
filter(lambda i: re.search(regexSub, i), fullList2))
If the examples are all truly as simple as those you listed, a regex is probably overkill. A simple solution would be to use string .split and .join. This would likely give better performance.
First split the url at the first period:
url = 'server1.example.com'
split_url = url.split('.', 1)
# ['server1', 'example.com']
Then you can use the sub to rejoin the url:
subbed_url = '.sub.'.join(split_url)
# 'server1.sub.example.com'
Of course you can do the split and the join at the same time
'.sub.'.join(url.split('.', 1))
Or create a simple function:
def sub_url(url):
return '.sub.'.join(url.split('.', 1))
To apply this to the list you can take several approaches.
A list comprehension:
subbed_list = [sub_url(url)
for url in url_list]
Map it:
subbed_list = map(sub_url, url_list)
Or my favorite, a generator:
gen_subbed = (sub_url(url)
for url in url_list)
The last looks like a list comprehension but gives the added benefit that you don't rebuild the entire list. It processes the elements one item at a time as the generator is iterated through. If you decide you do need the list later you can simply convert it to a list as follows:
subbed_list = list(gen_subbed)

Function Not Printing Desired Output

I am having issues with creating a function that takes a list of tuples and then returns one string which is the first character of each tuple. Below is my current code, but nothing it happening, I do not get a syntax error. Any help would be appreciated.
lst_of_tups = ([('hello', 'all'), ('music', 'playing'), ('celebration', 'station')])
def build_string(lst_of_tups):
final_str = ""
for tup in list_of_tups:
for item in tup:
final_str = final_str + item[0]
return final_str
print build_string
**** expected output: hampcs****
those string manipulation functions are error-prone: they define lots of variables, can return within inner loops, have unexpected side-effects...
Once you're used to list comprehensions, you can create such programs easily & with great execution performance (string concatenation is slow). One way:
def build_string(lst_of_tups):
return "".join([x[0] for y in lst_of_tups for x in y])
basically, it's just 2 loops (flattening the data) within a list comprehension to extract each first character from every string, joined together using str.join to rebuild the string.
Once you reach a return statement in a function, the function ends for good. The line
print build_string
cannot be reached. (Another problem is that the name build_string is not defined.)
Use your function like this:
result = build_string(lst_of_tups) # calls your function and puts the return value in the result variable
print result # print the result
Of course, the intermediary variable result is not necessary, you could just issue print build_string(lst_of_tups) as well.

How to add two odd lists into one list in python?

I am very new to Python, and I'm trying to combine elements from two lists and produce a string from the combination.
My variables are:
fro = ['USD']
to = ['AUD', 'CAD', 'EUR']
I want output like this in a string:
pairs = "USDAUD,USDCAD,USDEUR"
Thanks a ton in advance for your help.
Why not use a generator expression like this:
fro = ['USD']
to = ['AUD', 'CAD', 'EUR']
pairs = ','.join(fro[0] + x for x in to)
Note that from is a reserved keyword and is thus not a valid variable name.
Output:
>>>pairs
'USDAUD,USDCAD,USDEUR'
If you were ever curious as to whether something you wish to use as a variable name is a keyword (and thus an illegal variable name) or not, you can always check with something like this:
>>> import keyword
>>> keyword.iskeyword("from")
True
Elizion's answer is nice and succinct, but as a beginner you may want to approach it without using an intermediate/advanced structure like a generator:
fro = ['USD']
to = ['AUD', 'CAD', 'EUR']
pairs = ""
for word in to:
pairs += fro[0] + word + ","
Removing the trailing comma:
pairs = pairs[:-1]
Elizion is absolutely correct.
If you have list elements varies dynamically, you can use this line:
absolutely pythonic way!!
pair_elem = ','.join('%s%s' % (x, y) for y in to for x in fro)
And conventional way is like, iterate list elems:
for multiple in to:
for single in fro:
pairs = ",".join(single + multiple)

Generate a list of variables in SymPy [duplicate]

I am coding a function that solves an arbitrary number of simultaneous equations. The number of equations is set by one of the parameters of the function and each equation is built from a number of symbols - as many symbols as there are equations. This means that I can't simply hardcode the equations, or even the symbols needed to put together the equations; the function needs to be able to handle any number of equations. So, my question is, how do I produce a list of symbols?
I have one possible solution, but my gut tells me that it's not going to be very efficient. Please let me know if there is a better way of doing this.
I'm new to SymPy and am still feeling my way about. As far as I can see, Symbols need to be defined with a string. Therefore, I can produce a series strings via appending an incrementing number to a letter (say 't0', 't1', etc), add them to a list and then create the symbols using those strings as parameters. Those symbols would themselves be stored in a list and would be used to produce the equations.
def solveEquations(numEquations):
symbolNameList = []
symbolList = []
equationList = []
for i in range(numEquations):
name = 't' + str(i)
symbolNameList.append(name)
symbolList.append(Symbol(name))
for i in range(numEquations):
equation = 0
for sym in symbolList:
equation += sym ** i # Or whatever structure the equation needs
equationList.append(equation)
#Then go on to solve the equations...
Is this the best way of doing this, or is there a more efficient approach?
The symbols function can be used to easily generate lists of symbols
In [1]: symbols('a0:3')
Out[1]: (a₀, a₁, a₂)
In [2]: numEquations = 15
In [3]: symbols('a0:%d'%numEquations)
Out[3]: (a₀, a₁, a₂, a₃, a₄, a₅, a₆, a₇, a₈, a₉, a₁₀, a₁₁, a₁₂, a₁₃, a₁₄)
numbered_symbols("t") will return a generator that generates t0, t1, t2, etc. You can use the start parameter to choose a different starting value. And if you want to use dummy variables, use numbered_symbols("t", cls=Dummy).
Don't know if add any more useful information to the topic, but I use the following method to create a list of symbolic variables:
x = [sympy.symbols('x%d' % i) for i in range(3)]
And then I can use it normally in an equation:
eq = x[0]**2 + x[1]*2 + x[2]
print(sympy.diff(eq,x[0]))
>>> 2*x0
With locals() and dictionary comprehension, you could iteratively generate both symbols and python local variables with a similar name. For example:
>>> symbols_dict = dict(('a%d'%k, symbols('a%d'%k)) for k in range(3))
>>> locals().update(symbols_dict)
Checking that it works:
>>> print(expand((a0+a2)*(a0+a1**2)))
a0**2 + a0*a1**2 + a0*a2 + a1**2*a2
You could make a subclass of dict which automatically returns Symbols:
import sympy as sym
class SymDict(dict):
# http://stackoverflow.com/a/3405143/190597
def __missing__(self, key):
self[key]=sym.Symbol(key)
return self[key]
def solveEquations(numEquations):
symbol = SymDict()
symbolList = ['t'+str(i) for i in range(numEquations)]
equationList = [sum(symbol[s]**i for s in symbolList)
for i in range(numEquations)]
print(equationList)
solveEquations(3)
# [3, t0 + t1 + t2, t0**2 + t1**2 + t2**2]
I like the approach given by #j-p-sena and what I am going to suggest looks a lot like it. The difference is that you don't have to know how many symbols you are going to need -- you will just have access to as many as you need by index. Use the IndexedBase as your symbol:
>>> x = IndexedBase('x') # you've got access to a virtual array of x values
>>> solve(x[1]**2 + 1/x[4], x[4])
[-1/x[1]**2]
For display purposes you might want to create a replacement dictionary. To create numbered symbols you could do
>>> reps = dict(zip([x[i] for i in range(n_used+1)], numbered_symbols('c')))
>>> (x[2]**2 + 1/x[4]).subs(reps)
c2**2 + 1/c4
Or, if you are using less than 26 symbols you could use letters with
>>> reps = dict(zip([x[i] for i in range(n_used+1)], symbols('a:z')))
>>> (x[2]**2 + 1/x[4]).subs(reps)
c**2 + 1/e
BTW, x is an IndexedBase and x[1] is an Indexed object whose .base is x and whose .indices are a tuple of whatever numbers appear in the brackets. Both the IndexedBase and Indexed will show up in a .free_symbols query.
>>> (x[1,2] + 3).free_symbols
{x, x[1, 2]}
>>> x[1, 2].indices
(1, 2)
>>> x[1].base
x
Your approach is fine, though there's no need to store the symbol names separately (you can access a symbol's name via its name property).
Also, you could express the symbol creation a little more concisely (though no more efficiently), e.g.:
symbolList = map(lambda i: Symbol('t' + str(i)), xrange(numEquations))
However, for your use case (temporary variables), dummy variables are probably the way to go:
symbolList = map(Dummy, xrange(numEquations))
This isn't really any more efficient, since internally the Dummy class is also using a counter to generate unique names, but it's a bit cleaner and clearer.

Categories