updating tuple string and how to optimize my code - python-3.x

I have one list like that :
[`('__label__c091cb93-c737-4a67-95d7-49feecc6456c', 0.5), ('__label__96693d45-4dec-4b66-a2e2-621329d64b92', 0.498047)]`
I want to replace tuple element string value like this:
'__label__c091cb93-c737-4a67-95d7-49feecc6456c' to 'c091cb93-c737-4a67-95d7-49feecc6456c'
I try this :
l = [('__label__c091cb93-c737-4a67-95d7-49feecc6456c', 0.5), ('__label__96693d45-4dec-4b66-a2e2-621329d64b92', 0.498047)]
j = []
for x in l:
for y in x:
if type(y) == str:
z = y.replace('__label__',"")
j.append((z, x[1]))
print(j)
Output:
[('c091cb93-c737-4a67-95d7-49feecc6456c', 0.5), ('96693d45-4dec-4b66-a2e2-621329d64b92', 0.498047)]
how to optimize my code in pythonic way and any other way to update tuple value because tuple is immutable

You are right, tuples are immutables in Python, but lists are not. So you should be able to update the list l in-place.
Moreover, it looks like you already know the position of the element you have to modify and the position of the substring you want to remove, so you can avoid one loop and the replace function which will iterate once more over your string.
for i in range(len(l)):
the_tuple = l[i]
if isinstance(the_tuple[0], str) and the_tuple[0].startswith('__label__'):
l[i] = (the_tuple[0][len('__label__'):], the_tuple[1])
# you can also replace "len('__label__')" by "8" to increase performances
# but I think Python already optimizes it

You can use map function:
data = [('__label__c091cb93-c737-4a67-95d7-49feecc6456c', 0.5), ('__label__96693d45-4dec-4b66-a2e2-621329d64b92', 0.498047)]
def f(row): return row[0].replace('__label__', ''), row[1]
print(list(map(f, data)))

Related

Find the index of a tuple when iterating across the first element of the tuple

How can you identify the index of a tuple when looping through a list of tuples[0]?
List = [('SPAM', 1.0),('EGGS', 4.2),('SPAM', 4.4),('BACON', 9.0),('COFFEE', 2.3)]
for i,j in List:
if i == 'SPAM':
list.remove(???)
print(list)
I've tried to employ the Enumerate() function, but that didn't seem to give me the correct output either.
List.pop()
Doesn't pop the correct index all the time.
Can anyone help, please?
Enumeration does work:
l = [('SPAM', 1.0),('EGGS', 4.2),('SPAM', 4.4),('BACON', 9.0),('COFFEE', 2.3)]
for idx, (i,j) in enumerate(l):
if i == 'SPAM':
print("FOUND SPAN at index %d" % idx)
However, you shouldn't mutate the list while iterating over it, rather take a filtering approach like so:
l_new = [(i, j) for i, j in l if i != 'SPAM']
You can use del to delete the element at the given index:
List = [('SPAM', 1.0),('EGGS', 4.2),('SPAM', 4.4),('BACON', 9.0),('COFFEE', 2.3)]
for (i, (e1, e2)) in enumerate(List):
if e1 == 'SPAM':
del List[i]
print(List) # prints [('EGGS', 4.2), ('BACON', 9.0), ('COFFEE', 2.3)]

how to add characters from array into one string python

I'm trying to change characters from x into upper or lower character depending whether they are in r or c. And the problem is that i can't get all the changed characters into one string.
import unittest
def fun_exercise_6(x):
y = []
r = 'abcdefghijkl'
c = 'mnopqrstuvwxz'
for i in range(len(x)):
if(x[i] in r):
y += x[i].lower()
elif(x[i] in c):
y += x[i].upper()
return y
class TestAssignment1(unittest.TestCase):
def test1_exercise_6(self):
self.assertTrue(fun_exercise_6("osso") == "OSSO")
def test2_exercise_6(self):
self.assertTrue(fun_exercise_6("goat") == "gOaT")
def test3_exercise_6(self):
self.assertTrue(fun_exercise_6("bag") == "bag")
def test4_exercise_6(self):
self.assertTrue(fun_exercise_6("boat") == "bOaT" )
if __name__ == '__main__':
unittest.main()
Using a list as you are using is probably the best approach while you are figuring out whether or not each character should be uppered or lowered. You can join your list using str's join method. In your case, you could have your return statement look like this:
return ''.join(y)
What this would do is join a collection of strings (your individual characters into one new string using the string you join on ('').
For example, ''.join(['a', 'b', 'c']) will turn into 'abc'
This is a much better solution than making y a string as strings are immutable data types. If you make y a string when you are constructing it, you would have to redefine and reallocate the ENTIRE string each time you appended a character. Using a list, as you are doing, and joining it at the end would allow you to accumulate the characters and then join them all at once, which is comparatively very efficient.
If you define y as an empty string y = "" instead of an empty list you will get y as one string. Since when you declare y = [] and add an item to the list, you add a string to a list of string not a character to a string.
You can't compare a list and a string.
"abc" == ["a", "b", "c'] # False
The initial value of y in the fun_exercise_6 function must be ""

How can i optimise my code and make it readable?

The task is:
User enters a number, you take 1 number from the left, one from the right and sum it. Then you take the rest of this number and sum every digit in it. then you get two answers. You have to sort them from biggest to lowest and make them into a one solid number. I solved it, but i don't like how it looks like. i mean the task is pretty simple but my code looks like trash. Maybe i should use some more built-in functions and libraries. If so, could you please advise me some? Thank you
a = int(input())
b = [int(i) for i in str(a)]
closesum = 0
d = []
e = ""
farsum = b[0] + b[-1]
print(farsum)
b.pop(0)
b.pop(-1)
print(b)
for i in b:
closesum += i
print(closesum)
d.append(int(closesum))
d.append(int(farsum))
print(d)
for i in sorted(d, reverse = True):
e += str(i)
print(int(e))
input()
You can use reduce
from functools import reduce
a = [0,1,2,3,4,5,6,7,8,9]
print(reduce(lambda x, y: x + y, a))
# 45
and you can just pass in a shortened list instead of poping elements: b[1:-1]
The first two lines:
str_input = input() # input will always read strings
num_list = [int(i) for i in str_input]
the for loop at the end is useless and there is no need to sort only 2 elements. You can just use a simple if..else condition to print what you want.
You don't need a loop to sum a slice of a list. You can also use join to concatenate a list of strings without looping. This implementation converts to string before sorting (the result would be the same). You could convert to string after sorting using map(str,...)
farsum = b[0] + b[-1]
closesum = sum(b[1:-2])
"".join(sorted((str(farsum),str(closesum)),reverse=True))

iteration and matching items in lists

Am trying to check if elements of a list match elements of another. But there is a slight twist to the problem.
alist = ['949', '714']
blist = ['(714)824-1234', '(419)312-8732', '(949)555-1234', '(661)949-2867']
Am trying to match the elements of alist to the blist, but only the area code part(in blist). Here is my current code:
def match_area_codes(alist, blist):
clist =[]
for i in alist:
for j in blist:
if i in j:
clist.append(j)
return clist
The code works for the most part, except when there is a string matching the area code anywhere else in the list. It should only print:
['(714)824-1234', '(949)555-1234']
but it ends up printing
['(714)824-1234', '(949)555-1234', '(661)949-2867']
as there is a '949' in the last phone number. Is there a way to fix this?
You can use a regular expression to get the part within (...) and compare that part to alist.
import re
def match_area_codes(alist, blist):
p = re.compile(r"\((\d+)\)")
return [b for b in blist if p.search(b).group(1) in alist]
Example:
>>> alist = set(['949', '714'])
>>> blist = ['(714)824-1234', '(419)312-8732', '(949)555-1234', '(661)949-2867']
>>> match_area_codes(alist, blist)
['(714)824-1234', '(949)555-1234']
If you really really want to do it without regular expressions, you could, e.g., find the position of the ( and ) and thus get the slice from the string corresponding to the region code.
def match_area_codes(alist, blist):
find_code = lambda s: s[s.index("(") + 1 : s.index(")")]
return [b for b in blist if find_code(b) in alist]
However, I would strongly suggest to just take this as an opportunity for getting started with regular expressions. It's not all that hard, and definitely worth it!

How to get keys from nested dictionary of arbitrary length in Python

I have a dictionary object in python. Let's call it as dict. This object could contain another dictionary which may in turn contain another dictionary and so on.
dict = { 'k': v, 'k1': v1, 'dict2':{'k3': v3, 'k4':v4} , 'dict3':{'k5':v5, dict4:{'k6':v6}}}
This is just an example. Length of outermost dictionary could be anything. I want to extract keys from such dictionary object in following two ways :
get list of only keys.
[k,k1,k2,k3,k4,k5,k6]
get list of keys and its parent associated dictionary so something like this :
outer_dict_keys = [k ,dict2, dict3]
dict2_keys = [k3,k4]
dict3_keys = [k5, dict4]
dict4_keys = [k6]
Outermost dictionary dict length is always changing so I can not hard code anything.
What is best way to achieve above result ?
Use a mix of iteration and tail recursion. After quoting undefined names, making spacing uniform, and removing 'k2' from the first result, I came up with the code below. (Written and tested for 3.4, it should run on any 3.x and might on 2.7.) A key thing to remember is that the iteration order of dicts is essentially random, and varies with each run. Recursion as done here visit sub-dicts in depth-first rather than breadth-first order. For dict0, both are the same, But if dict4 were nested in dict2 rather than dict3, they would not be.
dict0 = {'k0': 0, 'k1': 1, 'dict2':{'k3': 3, 'k4': 4},
'dict3':{'k5': 5, 'dict4':{'k6': 6}}}
def keys(dic, klist=[]):
subdics = []
for key in sorted(dic):
val = dic[key]
if isinstance(val, dict):
subdics.append(val)
else:
klist.append(key)
for subdict in subdics:
keys(subdict, klist)
return klist
result = keys(dict0)
print(result, '\n', result == ['k0','k1','k3','k4','k5','k6'])
def keylines(dic, name='outer_dict', lines=[]):
vals = []
subdics = []
for key in sorted(dic):
val = dic[key]
if isinstance(val, dict):
subdics.append((key,val))
else:
vals.append(key)
vals.extend(pair[0] for pair in subdics)
lines.append('{}_keys = {}'.format(name, vals))
for subdict in subdics:
keylines(subdict[1], subdict[0], lines)
return lines
result = keylines(dict0)
for line in result:
print(line,)
print()
expect = [
"outer_dict_keys = ['k0', 'k1', 'dict2', 'dict3']",
"dict2_keys = ['k3', 'k4']",
"dict3_keys = ['k5', 'dict4']",
"dict4_keys = ['k6']"]
for actual, want in zip(result, expect):
if actual != want:
print(want)
for i, (c1, c2) in enumerate(zip(actual, want)):
if c1 != c2:
print(i, c1, c2)

Resources