Expand Variables in a List Python - python

Need to know how to expand variable inside list element
>>> one_more = "four"
>>> var_names = ["one", "two", "three_<expand variable one_more>"]
should get something like
['one', 'two', 'three_four']

Very basic:
In [1]: a="four"
In [2]: b="five"
In [3]: ['one', 'two', 'three_%s' % a]
Out[3]: ['one', 'two', 'three_four']
You could also join a list a variables:
In [5]: ['one', 'two', 'three_%s' % '_'.join((a,b))]
Out[5]: ['one', 'two', 'three_four_five']
Here is the same solution with str.format:
In [6]: ['one', 'two', 'three_{}'.format('_'.join((a,b)))]
Out[6]: ['one', 'two', 'three_four_five']

I presume you want to do a string replacement within a list. Here is an example fits your requirement.
one_more = "four"
var_names = ["one", "two", "three_<var>"]
print [x.replace("<var>", one_more) for x in var_names]
>>> ["one", "two", "three_four"]
If you want to have replace more than one pattern in one shot, you can do this:
a = "AA"
b = "BB"
var_names = ["one", "two", "three_$a", "four_$b"]
def batch_replace(str, lookup):
for pattern in lookup:
replacement = lookup[pattern]
str = str.replace(pattern, replacement)
return str
print [batch_replace(x, {"$a": a, "$b": b}) for x in var_names]
>>> ["one", "two", "three_AA", "four_BB"]

Related

lambda in lambda

Can anybody explain me whats wrong i am doing here -
multiArray = [
['one', 'two', 'three', 'four', 'five'],
['one', 'two', 'three', 'four', 'five'],
['one', 'two', 'three', 'four', 'five']
]
search ='four'
p1 = list(filter(lambda outerEle: search == outerEle, multiArray[0]))
p = list(filter(lambda multiArrayEle: list(filter(lambda innerArrayEle: search == innerArrayEle, multiArrayEle)), multiArray))
print (p1)
print (p)
The result i am getting here is
['four']
[['one', 'two', 'three', 'four', 'five'], ['one', 'two', 'three', 'four', 'five'], ['one', 'two', 'three', 'four', 'five']]
while i am expecting
[['four'],['four'],['four']]
In your second filter, you are using a list as a predicate (as opposed to simply a bool as you do in the first filter); now, this implicitly applies the built-in method bool to each element list, and for a list l, bool(l) is true exactly when l is non-empty:
In [4]: bool([])
Out[4]: False
In [5]: bool(['a'])
Out[5]: True
This allows you to pick out, for example, all the non-empty lists in a list of lists:
In [6]: ls = [['a'], [], ['b']]
In [7]: list(filter(lambda l: l, ls))
Out[7]: [['a'], ['b']]
Thus, in your case, at the end of the day, your filter ends up giving you all lists for which 'four' appears, which is all of them.
From your given example, it's not immediately obvious what you are trying to achieve as all the inputs are identical, but my guess is that it's something like the following:
In [19]: multiArray = [
...: ['one', 'two', 'three', 'four', 'five', 'four'],
...: ['one', 'two', 'three', 'for', 'five'],
...: ['one', 'two', 'three', 'four', 'five']
...: ]
In [20]: [list(filter(lambda x: x == search, l)) for l in multiArray]
Out[20]: [['four', 'four'], [], ['four']]
While #fuglede's answer is really the answer to your question, you can archive the result you want by changing your outer filter to map:
p = list(map(lambda multiArrayEle: list(filter(lambda innerArrayEle: search == innerArrayEle, multiArrayEle)), multiArray))

How to make "seen" hash with python dict?

In Perl one can do this:
my %seen;
foreach my $dir ( split /:/, $input ) {
$seen{$dir}++;
}
This is a way to remove duplicates by keeping track of what has been "seen". In python you cannot do:
seen = {}
for x in ['one', 'two', 'three', 'one']:
seen[x] += 1
The above python results in KeyError: 'one'.
What is python-y way of making a 'seen' hash?
Use a defaultdict for getting this behavior. The catch is that you need to specify the datatype for defaultdict to work for even those keys which don't have a value:
In [29]: from collections import defaultdict
In [30]: seen = defaultdict(int)
In [31]: for x in ['one', 'two', 'three', 'one']:
...: seen[x] += 1
In [32]: seen
Out[32]: defaultdict(int, {'one': 2, 'three': 1, 'two': 1})
You can use a Counter as well:
>>> from collections import Counter
>>> seen = Counter()
>>> for x in ['one', 'two', 'three', 'one']: seen[x] += 1
...
>>> seen
Counter({'one': 2, 'three': 1, 'two': 1})
If all you need are uniques, just do a set operation: set(['one', 'two', 'three', 'one'])
You could use a set:
>>> seen=set(['one', 'two', 'three', 'one'])
>>> seen
{'one', 'two', 'three'}
If you unroll seen[x] += 1 into seen[x] = seen[x] + 1, the problem with your code is obvious: you're trying to access seen[x] before you've assigned to it. Instead, you need to check if the key exists first:
seen = {}
for x in ['one', 'two', 'three', 'one']:
if x in seen:
seen[x] += 1 # we've seen it before, so increment
else:
seen[x] = 1 # first time seeing x

Converting String list to pure list in Python

I have a string type list from bash which looks like this:
inp = "["one","two","three","four","five"]"
The input is coming from bash script.
In my python script I would like to convert this to normal python list in this format:
["one","two","three","four","five"]
where all elements would be string, but the whole thin is represented as list.
I tried: list(inp)
it does not work. Any suggestions?
Try this code,
import ast
inp = '["one","two","three","four","five"]'
ast.literal_eval(inp) # will prints ['one', 'two', 'three', 'four', 'five']
Have a look at ast.literal_eval:
>>> import ast
>>> inp = '["one","two","three","four","five"]'
>>> converted_inp = ast.literal_eval(inp)
>>> type(converted_inp)
<class 'list'>
>>> print(converted_inp)
['one', 'two', 'three', 'four', 'five']
Notice that your original input string is not a valid python string, since it ends after "[".
>>> inp = "["one","two","three","four","five"]"
SyntaxError: invalid syntax
The solution using re.sub() and str.split() functions:
import re
inp = '["one","two","three","four","five"]'
l = re.sub(r'["\]\[]', '', inp).split(',')
print(l)
The output:
['one', 'two', 'three', 'four', 'five']
you can use replace and split as the following:
>>> inp
"['one','two','three','four','five']"
>>> inp.replace('[','').replace(']','').replace('\'','').split(',')
['one', 'two', 'three', 'four', 'five']

Changing values of a list by getting them from a dictionary (Python)

So I have this list that looks like this:
['One', 'Two', 'Three', 'Four']
['Five', 'Six', 'Seven']
so, a list with 2 elements
lst = [['One', 'Two', 'Three', 'Four'], ['Five', 'Six', 'Seven']]
And then I have also a dictionary that I declared like this:
numberDict = dict()
numberDict["One"] = "First"
numberDict["Two"] = "Second"
numberDict["Three"] = "Third"
numberDict["Four"] = "Fourth"
numberDict["Five"] = "Fifth"
numberDict["Six"] = "Sixth"
numberDict["Seven"] = "Seventh"
My question: How can I get me list to look like this? To replace its values with the dictionary ones?
lst = [['First', 'Second', 'Third', 'Fourth'], ['Fifth', 'Sixth', 'Seventh']]
Use a list comprehension:
>>> list_of_list = [['One', 'Two', 'Three', 'Four'], ['Five', 'Six', 'Seven']]
>>> [[numberDict.get(value, "") for value in lst] for lst in list_of_list]
[['First', 'Second', 'Third', 'Fourth'], ['Fifth', 'Sixth', 'Seventh']]
As an aside, note that you can also initialize the numbersDict in a single go
>>> numbers_dict = {"One": "First",
... "Two": "Second",
... "Three": "Third",
... "Four": "Fourth",
... "Five": "Fifth",
... "Six": "Sixth",
... "Seven": "Seventh"}

Substitutions with elements from a list with re.sub?

What is the best way to perform substitutions with re.sub given a list? For example:
import re
some_text = 'xxxxxxx#yyyyyyyyy#zzzzzzzzz#'
substitutions = ['ONE', 'TWO', 'THREE']
x = re.sub('#', lambda i: i[0] substitutions.pop(0), some_text) # this doesn't actually work
The desired output would be:
some_text = 'xxxxxxxONEyyyyyyyyyTWOzzzzzzzzzTHREE'
You just have a syntax error in your lambda:
>>> substitutions = ['ONE', 'TWO', 'THREE']
>>> re.sub('#', lambda _: substitutions.pop(0), some_text)
'xxxxxxxONEyyyyyyyyyTWOzzzzzzzzzTHREE'
If you don't want to modify the list, you can wrap it an iterable.
>>> substitutions = ['ONE', 'TWO', 'THREE']
>>> subs = iter(substitutions)
>>> re.sub('#', lambda _: next(subs), some_text)
'xxxxxxxONEyyyyyyyyyTWOzzzzzzzzzTHREE'
One way (there's probably a better one, I don't really know Python) is to compile the regular expression, then use that sub instead:
import re
some_text = 'xxxxxxx#yyyyyyyyy#zzzzzzzzz#'
substitutions = ['ONE', 'TWO', 'THREE']
pattern = re.compile('#')
x = pattern.sub(lambda i: substitutions.pop(0), some_text)
Here's a demo.
The code is almost correct, it needs a slight correction of a syntax error:
import re
some_text = 'xxxxxxx#yyyyyyyyy#zzzzzzzzz#'
substitutions = ['ONE', 'TWO', 'THREE']
x = re.sub('#', lambda i: substitutions.pop(0), some_text) # the error was in the lambda function

Categories