Bug free version of string substitution [duplicate] - python

This question already has answers here:
Replacing multiple similar strings
(1 answer)
How to replace two things at once in a string?
(6 answers)
How to replace multiple substrings of a string?
(28 answers)
Closed 4 years ago.
I am trapped in a quite straight forward problem, but after some tweak, I simply cannot find an easy and efficient algorithm to do this.
So basically I have a string, which contains certain elements, for instance:
l = "test %1, %13, %14, %15"
And a map:
dict = {"%1": "%33", "%13": "%14", "%14", "%15", "%15": "%17"}
And I would like to do the following stuff:
for k in dict.keys():
l = l.replace(k, dict[k])
So what I am expecting is:
l = "test %33, %14, %15, %17"
But apparently this is not feasible, since there are some conflict between keys and values. So the above code would output:
l = "test %33, %17, %17, %17"
Sorry for such native problem, but how should I solve this and get my expected output? Note that the length of each key/value is not fixed, so I cannot do something like:
m_idx = l_copy.find(key)
l = l[:m_idx] + dict[key] + l[m_idx+len(key):]
Because the length is not fixed, the above code is still buggy.
Am I clear on this? Any suggestion would be appreciated very much!
======= update
So all keys follow this pattern of %[0-9]+.

You can use re.sub with a lambda:
import re
l = "test %1, %13, %14, %15"
_dict = {"%1": "%33", "%13": "%14", "%14":"%15", "%15": "%17"}
new_l = re.sub('%\d+', lambda x:_dict[x.group()], l)
Output:
'test %33, %14, %15, %17'
You can use dict.get to prevent a KeyError by providing a default value should the key not be present in _dict:
new_l = re.sub('%\d+', lambda x:_dict.get(x.group(), x.group()), l)

Related

How to make a list from a query? [duplicate]

This question already has answers here:
How to modify list entries during for loop?
(10 answers)
Closed 11 months ago.
I run a query and want to make a list from this query. I only need those select items, which I got, but I can't get rid of "," in lst.
I tried replace but it didn't work.
query = """
select
supplier_no_and_name,
accepted,
rejected,
pending,
tdc
from edl_current.supplier_warranty_cost_recovery_warranty_alteryx
where claim_date > "2021-01-01"
"""
lst = query.split()
lst = lst[1-len(lst):len(lst)-13]
for i in range(len(lst)):
lst[i].replace(',',"")
print(lst)
The output is following:
['supplier_no_and_name,', 'accepted,', 'rejected,', 'pending,', 'tdc']
replace method has a return value which is string meaning it doesn't update the original value itself. So, you need to assign with a new value using same variable or anything.
lst[i] = lst[i].replace(',',"")
str.rstrip() and list comprehension would be simpler.
# for i in range(len(lst)):
# lst[i]=lst[i].replace(',',"")
l = [ x.rstrip(',') for x in lst ]
lst = l[:l.index('tdc')+1] # for making same output.
Try this:-
query = """
select
supplier_no_and_name,
accepted,
rejected,
pending,
tdc
from edl_current.supplier_warranty_cost_recovery_warranty_alteryx
where claim_date > "2021-01-01"
"""
lst = query.split()
lst = lst[1-len(lst):len(lst)-13]
for i in range(len(lst)):
lst[i] = lst[i].replace(',', "")
d = ' '.join(lst)
print(d)
Things you should follow next time you ask questions on stack overflow.
Add the expected output in proper format.
Show the things that you've tried in the post.
Frame your question properly and always add error message if found any.
Most importantly search the question on stack overflow before posting it
85 % of time you'll get the answers without posting.
Your current solution is super brittle in that you need to know in advance the exact number of words in your SQL statement. I think you want to try to be a little more flexible and pick out the SELECT and FROM clauses:
query = """
select
supplier_no_and_name,
accepted,
rejected,
pending,
tdc
from edl_current.supplier_warranty_cost_recovery_warranty_alteryx
where claim_date > "2021-01-01"
"""
query_parts = [
p.strip(",")
for p
in query.replace("\n", " ").split()
if p
]
select_index = query_parts.index("select")
from_index = query_parts.index("from")
lst = query_parts[select_index+1 : from_index]
print(lst)
This should give you:
['supplier_no_and_name', 'accepted', 'rejected', 'pending', 'tdc']
Without being sensitive to the number of words or columns.
Since strings are immutable, their replace() method returns a new string with the modifications as opposed to doing them "in place". This means you have to explicitly replace the values in the list.
for i, value in enumerate(lst):
lst[i] = value.replace(',', '')

create python dictionary with same function but different parameters [duplicate]

This question already has an answer here:
Dictionary With Lambda Values Updates All Entries
(1 answer)
Closed 1 year ago.
Hi this puzzeles me for a while now:
I want to add to an existing dictionary a new key with a specific function (myfun) but using different parameters for the same function:
dct = {}
params = {'a':[10,20],'b':[-10,10]}
def myfun(x,y):
return (x+y)
print(myfun(*params['a'])) #desired output for dct['a'](1,1) = 30
print(myfun(*params['b'])) #desired output for dct['b'](1,1) = 0
for key in params.keys():
dct[key]=lambda x,y: myfun(params[key][0]*x,params[key][1]*y)
print(dct['a'](1,1)) # should be 30
print(dct['b'](1,1)) # should be 0
but apparently it keeps only the last key (in this case 'b').
Any ideas?
Thanks #Chris:
use lambda-parameters initialized:
dct[key]=lambda x,y,xx=params[key][0],yy=params[key][1]: myfun(xx*x,yy*y)
this resolved my question!

Find the index of a value in a list, that is also inside of a string, using the any() function [duplicate]

This question already has answers here:
Get the first item from an iterable that matches a condition
(18 answers)
Closed 1 year ago.
Sorry if the question is a little confusing, but basically I have the following data:
useable = ['osc_1_', 'osc_2_', 'osc_3_', 'sample_', 'filter_1_', 'filter_2_', 'filter_fx_', 'lfo_1_', 'lfo_2_', 'lfo_3_', 'lfo_4_', 'lfo_5_', 'lfo_6_', 'lfo_7_', 'lfo_8_', 'random_1_', 'random_2_', 'random_3_', 'random_4_', 'env_1_', 'env_2_', 'env_3_', 'env_4_', 'env_5_', 'env_6_', 'chorus_', 'compressor', 'delay', 'distortion', 'phaser', 'flanger', 'reverb', 'equalizer']
I also have a string value: x = 'filter_fx_formant_x'
I'm using the following function to return 'True' if x contains a value that can be found in useable,
if any(useable in x for useable in useable):
ex: 'filter_fx_' is in both a substring of x and a value in useable.
Now here's my question: How can I get the index value of the item that can be found in a substring of x?
Is there a better way other than any()? Am I missing something obvious? Let me know if you can think of anything.
this You can use if You want to get the index:
useable = ['osc_1_', 'osc_2_', 'osc_3_', 'sample_', 'filter_1_', 'filter_2_', 'filter_fx_', 'lfo_1_', 'lfo_2_', 'lfo_3_', 'lfo_4_', 'lfo_5_', 'lfo_6_', 'lfo_7_', 'lfo_8_', 'random_1_', 'random_2_', 'random_3_', 'random_4_', 'env_1_', 'env_2_', 'env_3_', 'env_4_', 'env_5_', 'env_6_', 'chorus_', 'compressor', 'delay', 'distortion', 'phaser', 'flanger', 'reverb', 'equalizer']
x = 'filter_fx_formant_x'
for index, item in enumerate(useable):
if item in x:
print(index, item)
If your concern is to use any(), one way to implement your logic would be by the combination of map and str.contains()
any(map(x.__contains__, useable))
Output:
True
if you just want to get the first index if x contains substring from the list, you can implement same thing in an if conditional
>>mask = list(map(x.__contains__, useable))
>>if any(mask):
print(mask.index(True))
6
This is what next+enumerate allows:
try:
idx, found = next((i, useable) for i, useable in enumerate(useables) if useable in x):
except StopIteration:
# No hits found
else:
# idx is now the index of the first item to hit, found is the value
If you're guaranteed to have a hit for whatever reason, the try/except/else isn't needed.
It should be like this instead:
if (any(substring in x for substring in useable)):

How can I get Python to automatically create missing key/value pairs in a dictionary? [duplicate]

This question already has answers here:
Is there a standard class for an infinitely nested defaultdict?
(6 answers)
Closed 9 years ago.
I'm creating a dictionary structure that is several levels deep. I'm trying to do something like the following:
dict = {}
dict['a']['b'] = True
At the moment the above fails because key 'a' does not exist. At the moment I have to check at every level of nesting and manually insert an empty dictionary. Is there some type of syntactic sugar to be able to do something like the above can produce:
{'a': {'b': True}}
Without having to create an empty dictionary at each level of nesting?
As others have said, use defaultdict. This is the idiom I prefer for arbitrarily-deep nesting of dictionaries:
def nested_dict():
return collections.defaultdict(nested_dict)
d = nested_dict()
d[1][2][3] = 'Hello, dictionary!'
print(d[1][2][3]) # Prints Hello, dictionary!
This also makes checking whether an element exists a little nicer, too, since you may no longer need to use get:
if not d[2][3][4][5]:
print('That element is empty!')
This has been edited to use a def rather than a lambda for pep8 compliance. The original lambda form looked like this below, which has the drawback of being called <lambda> everywhere instead of getting a proper function name.
>>> nested_dict = lambda: collections.defaultdict(nested_dict)
>>> d = nested_dict()
>>> d[1][2][3]
defaultdict(<function <lambda> at 0x037E7540>, {})
Use defaultdict.
Python: defaultdict of defaultdict?
Or you can do this, since dict() function can handle **kwargs:
http://docs.python.org/2/library/functions.html#func-dict
print dict(a=dict(b=True))
# {'a': {'b' : True}}
If the depth of your data structure is fixed (that is, you know in advance that you need mydict[a][b][c] but not mydict[a][b][c][d]), you can build a nested defaultdict structure using lambda expressions to create the inner structures:
two_level = defaultdict(dict)
three_level = defaultdict(lambda: defaultdict(dict))
four_level = defaultdict(lamda: defaultdict(lambda: defaultdict(dict)))

Python unpack list for use in formatted string [duplicate]

This question already has answers here:
Pythonic way to print list items
(13 answers)
Closed 3 years ago.
I have a string that I am dynamically creating based off user input. I am using the .format function in Python to add a list into the string, but I would like to remove the quotes and brackets when printing.
I have tried:
return (('{} is {}x effective against {}').format(opponentType, overallHitMultiplier, [str(x) for x in playerTypes]))
and
return return (('{} is {}x effective against {}').format(opponentType, overallHitMultiplier, playerTypes))
which both return a string that looks like this:
fighting is 2x effective against ['normal', 'ghost']
but I would like it to return something like:
fighting is 2x effective against normal, ghost
The length of the list is variable so I can't just insert the list elements one by one.
Here is a more complete response:
def convert_player_types_to_str(player_types):
n = len(player_types)
if not n:
return ''
if n == 1:
return player_types[0]
return ', '.join(player_types[:-1]) + f' and {player_types[-1]}'
>>> convert_player_types_to_str(['normal'])
'normal'
>>> convert_player_types_to_str(['normal', 'ghost'])
'normal and ghost'
>>> convert_player_types_to_str(['normal', 'ghost', 'goblin'])
'normal, ghost and goblin'

Categories