how to modify list of actual variables in python - python

I want to do the same thing to a list of objects. I can call a function on all 3 of them like:
x = double(x)
y = double(y)
z = double(z)
but even by pre-modern standards this seems hideous. I do
In [4]: z = 0
In [5]: x = 0
In [6]: y = 0
In [7]: items = [x, y, z]
In [8]: for item in items:
...: item = 5
...:
In [9]: print(x)
0
and no dice. How do you operate on a list of variables, I'm reading getattr and it doesn't seem to work for me
I want to iterate over x, y, and z in this case, and set them all equal to 5 in two lines of code- the for item in items, and then modify each item
For now, I get odd behavior, like all items are directly equal to each other:
In [11]: for item in items:
print item is x
....:
True
True
True
In [12]: for item in items:
print item is y
....:
True
True
True
I don't actually want a list, I want them to stay in memory with the same name so I can immediately do:
return {'income': income, 'ex_date': exdate, ...}
I didn't give enough info, but here is the goal, all 4 will have to be handled separately:
total_income = self.get_total_income(portfolio_id)
short_term = get_short_term(distros, 'ST')
long_term = get_lt(distros, 'LT')
total_distributions = self.get_totals(portfolio_id)
items = [total_income, short_term, long_term, total_distributions]
for item in items:
do the same thing
return {'total_income': total_income, 'short_term': short_term, 'long_term': long_term, 'total_distributions': total_distributions}

The problem with your loop is that all you do is assign 5 to the name item, but never do anything to the original list.
To modify a list (or, more precise, get a new list of modified values) you can either use a list comprehension or map a function to all elements of a list.
>>> items = [0, 0, 0]
>>> [float(x) for x in items]
[0.0, 0.0, 0.0]
>>> map(float, items)
[0.0, 0.0, 0.0]
Another example:
>>> items = [1,2,3]
>>> [x*10 for x in items]
[10, 20, 30]
>>> map(str, items)
['1', '2', '3']
edit in response to your comment on the question:
ya, I used a few yesterday. I don't actually want a list though, I want them to stay in memory with the same name
In that case, use a dictionary as your data structure instead of n lone variables. Example:
>>> my_values = {'x': 1, 'y': 2, 'z':3}
>>> my_values['y']
2
You can modify all your values by a given rule with a dictionary comprehension.
>>> my_values = {key:value*2 for key, value in my_values.items()}
>>> my_values
{'y': 4, 'x': 2, 'z': 6}

Here you even don't need to use list comprehensions. In your particular case this is enough:
x = y = z = 5

If you want your variables to stay in the memory with same names but with different values you can do:
[x, y, z] = [5 for _ in items]
or
[x, y, z] = [double(i) for i in items]

What about that?
x = 1
y = 2
z = 3
l = [x, y, z]
l = [i**2 for i in l]
x, y, z = l
print(x, y, z)
1 4 9

How do you operate on a list of variables
Generally speaking you don't. If you have values you want to operate on as a list then you store them in a list not in individual variables. Or you can store them as items in a dictionary, or attributes of an object, just don't put them in separate variables.
For the particular case you asked about you could do this:
x, y, z = map(double, [x, y, z])
or for your other example:
total_income = self.get_total_income(var)
short_term = get_short_term(var)
long_term = get_lt(var)
total_distributions = self.get_totals(var)
items = [total_income, short_term, long_term, total_distributions]
result = {
'total_income': total_income,
'short_term': short_term,
'long_term': long_term,
'total_distributions': total_distributions
}
# N.B. Using list(...) to avoid modifying the dict while iterating.
for key, value in list(result.items()):
result[key] = do_something(value)
return result

Related

Sorting enumerated elements in a list using another list as an order

I have a master list:
l = ['gala_apple', 'gala_lime', 'fuji_apple', 'fuji_lime']
Through some manipulation, I end up with a variant of l:
r = [
'fuji_apple_1',
'fuji_apple_2',
'fuji_lime_1',
'fuji_lime_2',
'gala_apple_1',
'gala_apple_2',
'gala_apple_3',
'gala_lime_1',
'gala_lime_2',
'gala_lime_3',
]
Using the master list l as a reference, I want the list r to be ordered like:
r = [
'gala_apple_1',
'gala_lime_1',
'gala_apple_2',
'gala_lime_2',
'gala_apple_3',
'gala_lime_3',
'fuji_apple_1',
'fuji_lime_1',
'fuji_apple_2',
'fuji_lime_2',
]
I.e. (gala_apple_X, gala_lime_X, gala_apple_Y, gala_lime_Y, ...), (fuji_apple_X, fuji_lime_X, fuji_apple_Y, fuji_lime_Y, ...)
First use l to derive sort orders for the type (gala, fuji, etc) and fruit (apple, lime, etc):
>>> taxonomy = {}
>>> for x in l:
... t, f = x.split("_")
... taxonomy.setdefault(t, []).append(f)
...
>>> type_order = {t: i for i, t in enumerate(taxonomy)}
>>> fruit_orders = {tuple(v) for v in taxonomy.values()}
>>> assert len(fruit_orders) == 1
>>> fruit_order = {t: i for i, t in enumerate(fruit_orders.pop())}
That gives us:
>>> type_order
{'gala': 0, 'fuji': 1}
>>> fruit_order
{'apple': 0, 'lime': 1}
Then use that to define a sort key function which sorts first on type (the first field), then on number (the third field), then on fruit (the second field), using the established sort order for type and fruit, and numeric sort order for the number:
>>> def sort_key(x):
... t, f, n = x.split("_")
... return type_order[t], int(n), fruit_order[f]
...
Then you can use that key to sort r:
>>> print(*sorted(r, key=sort_key), sep='\n')
gala_apple_1
gala_lime_1
gala_apple_2
gala_lime_2
gala_apple_3
gala_lime_3
fuji_apple_1
fuji_lime_1
fuji_apple_2
fuji_lime_2
This works, but for scaling to more variables (e.g. gala_grape, gala_pear), you need to change the for-loop and, in general, the algorithm isn't very efficient.
r2 = []
for apple, lime in zip(l[0::2], l[1::2]):
for i in range(len(r)):
a_i = f'{apple}_{i}'
if a_i in r:
r2.extend([a_i, f'{lime}_{i}'])
print(r2)

Compare List A against List B such that whenever any values in A is similar to that of B, it will replace the value of A with that of B

I am relatively new to python and would like to see if this is possible.
Let say I have two lists:
#List of Applications(<100 total)
X = ["Microsoft", "Apple", "Nike", "Adidas", ...]
#Imaginary websites that belongs to each application (>10k total)
Y = ["microsoft.com/123", "microsoft.com/456", "GoldenApple.com",...]
From here I want to compare Y against X, such that whenever any part of a value in Y is a substring of X, then that value of Y will be changed to that of X.
Eg.
"microsoft.com/123" becomes "Microsoft"
"microsoft.com/456" becomes "Microsoft"
"GoldenApple.com" becomes "Apple".
Based on your comments (...string from X should be substring of value in Y...):
X = ["Microsoft", "Apple", "Nike", "Adidas"]
Y = ["microsoft.com/123", "microsoft.com/456", "GoldenApple.com"]
# put values from X/Y to lowercase:
X_map = {v.lower(): v for v in X}
Y = [v.lower() for v in Y]
# substitute:
out = []
for a in Y:
for b in X_map:
if b in a:
out.append(X_map[b])
break
else:
out.append(a)
print(out)
Prints:
['Microsoft', 'Microsoft', 'Apple']

'for' loop does not loop correctly

a=[['kyle','movie_1','c_13'],
['blair','food','a_29'],
['reese','movie_2','abc_76']]
b=['df.movie_1',
'ghk.food',
'df.movie_2']
x = {}
for i in b:
y = i.split('.')
for j in a:
if y[1] in j : x[y[0]]=j
print(x)
This is my code to check if there is string inside a list a .
The output that I got is
{'df': ['reese', 'movie_2', 'abc_76'], 'ghk': ['blair', 'food', 'a_29']}
My desired output is
{'df': [['kyle','movie_1','c_13'],['reese', 'movie_2', 'abc_76']], 'ghk': ['blair', 'food', 'a_29']}
The cause is that the value would be cover when it exists x['df'].
You could use defaultdict to save them(A little different from you expect, though.But it is very easy):
from collections import defaultdict
a = [['kyle', 'movie_1', 'c_13'],
['blair', 'food', 'a_29'],
['reese', 'movie_2', 'abc_76']]
b = ['df.movie_1',
'ghk.food',
'df.movie_2']
x = defaultdict(list)
for i in b:
y = i.split('.')
for j in a:
if y[1] in j:
x[y[0]].append(j)
print(x)
# defaultdict(<class 'list'>, {'df': [['kyle', 'movie_1', 'c_13'], ['reese', 'movie_2', 'abc_76']], 'ghk': [['blair', 'food', 'a_29']]})
As mentioned in a previous answer, the problem is that your loops end up overwriting the value of x[y[0]]. Based on your desired output, what you need is to append to a list instead. There is already a nice solution using defaultdict. If instead you want to just use standard list, this is one way to do it:
a = [
['kyle','movie_1','c_13'],
['blair','food','a_29'],
['reese','movie_2','abc_76']]
b = [
'df.movie_1',
'ghk.food',
'df.movie_2']
x = {}
for i in b:
y = i.split('.')
for j in a:
if y[1] in j:
if y[0] not in x: # if this is the first time we append
x[y[0]] = [] # make it an empty list
x[y[0]].append(j) # then always append
print(x)
Hope This works:
A single line code
Code:
op_dict={}
[op_dict.setdefault(x.split('.')[0], []).append(y) for x in b for y in a if x.split('.')[1] in y]
Output:

How to search tuple with three elements inside list

I have a list as below
tlist=[(‘abc’,HYD,’user1’), (‘xyz’,’SNG’,’user2’), (‘pppp’,’US’,’user3’), (‘qq’,’HK’,’user4’)]
I want to display the second field tuple of provided first field of tuple.
Ex:
tlist(‘xyz’)
SNG
Is there way to get it?
A tuple doesn't have a hash table lookup like a dictionary, so you will need to loop through it in sequence until you find it:
def find_in_tuple(tlist, search_term):
for x, y, z in tlist:
if x == search_term:
return y
print(find_in_tuple(tlist, 'xyz')) # prints 'SNG'
If you plan to do this multiple times, you definitely want to convert to a dictionary. I would recommend making the first element of the tuple the key and then the other two the values for that key. You can do this very easily using a dictionary comprehension.
>>> tlist_dict = { k: (x, y) for k, x, y in tlist } # Python 3: { k: v for k, *v in tlist }
>>> tlist_dict
{'qq': ['HK', 'user4'], 'xyz': ['SNG', 'user2'], 'abc': ['HYD', 'user1'], 'pppp': ['US', 'user3']}
You can then select the second element as follows:
>>> tlist_dict['xyz'][0]
'SNG'
If there would be multiple tuples with xyz as a first item, use the following simple approach(with modified example):
tlist = [('abc','HYD','user1'), ('xyz','SNG','user2'), ('pppp','US','user3'), ('xyz','HK','user4')]
second_fields = [f[1] for f in tlist if f[0] == 'xyz']
print(second_fields) # ['SNG', 'HK']

How to read a graph from a file in python to get its adjacency list?

I am reading from a file which has numbers which represent a graph and its adjacency list.First number is the vertex and the remaining are the neighbors.
Suppose if i have a string of space separated numbers stored in string: 1 2 3 4.
How do i split it such that x=1 and y is a list [2,3,4]?
y=[]
g=open('graph','r')
for line in g:
x,y=line.split()
In Python 3 you could do:
x, *y = line.split()
but in Python 2 you need to split to one variable first, then assign to x and y:
values = line.split()
x, y = values[0], values[1:]
If these need to be integers instead of strings, you need to map the values to int() first:
x, *y = map(int, line.split())
or, Python 2 again:
values = map(int, line.split())
x, y = values[0], values[1:]
Python 3 demo:
>>> x, *y = '1 2 3 4'.split()
>>> x, y
('1', ['2', '3', '4'])
>>> x, *y = map(int, '1 2 3 4'.split())
>>> x, y
(1, [2, 3, 4])
Python 2:
>>> values = '1 2 3 4'.split()
>>> x, y = values[0], values[1:]
>>> x, y
('1', ['2', '3', '4'])
>>> values = map(int, '1 2 3 4'.split())
>>> x, y = values[0], values[1:]
>>> x, y
(1, [2, 3, 4])
Here's a solution using Namedtuple [1] to store the data in an object oriented way.
Namedtuple is a generator to create small classes for storing data. The generated classes can print themselves, which is nice for debugging. However these objects are immutable, to change anything you must create new objects.
from collections import namedtuple
VertexInfo = namedtuple("VertexInfo", "vert, adj")
graph = []
g = open('graph','r')
for line in g:
nums = line.split()
info = VertexInfo(vert=nums[0], adj=nums[1:])
graph.append(info)
You can get the first vertex number with:
graph[0].vert
And the first adjacency list with
graph[0].adj
[1] http://docs.python.org/2/library/collections.html#collections.namedtuple

Categories