Python: elegant and save coding way to create several list - python

Normally in order to store result in several lists in python, i create before the loop the corresponding empty lists.
A = []
B = []
c = []
D = []
E = []
F = []
for i in range(100):
# do some stuff
i there a method to create the lists in a single code line (or few)?

If the lists are logically similar (I hope so, because one hundred different variables is violence on programmer), create a dictionary of lists:
list_names = ['a', 'b', 'c' ]
d = {name:[] for name in list_names}
This creates a dictionary:
d = {'a': [], 'b': [], 'c': []}
where you can access individual lists:
d['a'].append(...)
or work on all of them at once:
for v in d.itervalues():
v.append(...)
The further advantage over individual lists is that you can pass your whole dict to a method.

You can use an object:
>>> from string import ascii_uppercase
>>> class MyLists(object):
def __init__(self):
for char in ascii_uppercase:
setattr(self, char, [])
>>> l = MyLists()
>>> l.A
[]
>>> l.B
[]

a, b, c, d, e, f = [], [], [], [], [], []

lists = ([] for _ in range(6))
lists[5].append(...)
or
A, B, C, D, E, F = ([] for _ in range(6))
or with defaultdict
d = defaultdict(list)
d['F'].append(...)

Related

List comprehension using f-strings

I have three variables
a = 1
b = 2
c = 3
and I want to have a string like 'a=1, b=2, c=3'
so, I use f-string,
x = ''
for i in [a, b, c]:
x += f"{i=}"
but it gives,
x
'i=1, i=2, i=3, '
how do I make the i to be a, b, and c?
The list [a, b, c] is indistiguishable from the list [1, 2, 3] -- the variables themselves are not placed in the list, their values are, so there is no way to get the variable names out of the list after you've created it.
If you want the strings a, b, c, you need to iterate over those strings, not the results of evaluating those variables:
>>> ', '.join(f"i={i}" for i in "abc")
'i=a, i=b, i=c'
If you want to get the values held by the variables with those names, you can do this by looking them up in the globals() dict:
>>> a, b, c = 1, 2, 3
>>> ', '.join(f"{var}={globals()[var]}" for var in "abc")
'a=1, b=2, c=3'
but code that involves looking things up in globals() is going to be really annoying to debug the first time something goes wrong with it. Any time you have a collection of named values that you want to iterate over, it's better to just put those values in their own dict instead of making them individual variables:
>>> d = dict(a=1, b=2, c=3)
>>> ', '.join(f"{var}={val}" for var, val in d.items())
'a=1, b=2, c=3'
A list doesn't remember the names of variables assigned to it. For that, you need a dictionary.
x = ""
my_dict = {'a': a, 'b': b, 'c': c}
for k, v in my_dict.items():
x += f"{k}={v}, "
Using gloabls is not always a good idea if you want a solution that aovid using them you can inspect the variables that are declare using inspect module, there is thread regarding the getting the name of varibles here, from were the I took the function.
import inspect
def retrieve_var(var):
callers_local_vars = inspect.currentframe().f_back.f_locals.items()
return [var_name for var_name, var_val in callers_local_vars if var_val is var]
and now you can use a loop as similar to that you where using
a, b, c = 1, 2, 3
x = ''
for i in [a, b, c]:
var = retrieve_var(i)
x += f"{var[0]}={i}, "

How can I print from a dictionary?

I am wondering how I can print all keys in a dictionary on one line and values on the next so they line up.
The task is to create a solitaire card game in python. Made most of it already but I wish to improve on the visual. I know how to use a for loop to print lines for each value and key, but the task I'm doing in school asks me to do it this way. I also just tried to create new lists for each line and "print(list1)" print(list2) but that just looks ugly.
FireKort ={
'A': None,#in my code i have the cards as objects here with value
#and type
'B': None,#ex. object1: 8, cloves; object2: King, hearts
'C': None,
'D': None,
'E': None,
'F': None,
'G': None,
'H': None
}
def f_printK():
global FireKort
for key in FireKort:
print('Stokk:',key,' Gjenstående:',len(FireKort[key]))
try:
print(FireKort[key][0].sort, FireKort[key][0].valør)
except:
print('tom')
##here are the lists i tried:
## navn=[]
## kort=[]
## antall=[]
## for key in FireKort:
## navn.append((key+' '))
## kort.append([FireKort[key][0].sort,FireKort[key][0].valør])
## antall.append( str(len(FireKort[key])))
## print(navn)
## print(kort)
## print(antall)
A B C D E F G H
[♦9][♣A][♠Q][♣8][♦8][♣J][♣10][♦7]
4 4 4 4 4 4 4 4
Have you try to use pprint?
The pprint module provides a capability to “pretty-print arbitrary Python data structures
https://docs.python.org/2/library/pprint.html
Try this:
d = { ... }
keys = [ str(q) for q in d.keys() ]
values = [ str(q) for q in d.values() ]
txts = [ (str(a), str(b)) for a, b in zip(keys, values) ]
sizes = [ max(len(a), len(b)) for a, b in txts ]
formats = [ '%%%ds' % q for q in sizes ]
print(' '.join(a % b for a, b in zip (formats, keys)))
print(' '.join(a % b for a, b in zip (formats, values)))
In short:
first we get str values of keys and values of dictionary d (since we're going to use them twice, we might as well store them locally)
we calculate max size of each "column"
we create formats for % operator
and we print
It could be done using ljust method of str.
Example:
d = {'A':'some','B':'words','C':'of','D':'different','E':'length'}
keys = list(d.keys())
values = list(d.values())
longest = max([len(i) for i in keys]+[len(i) for i in values])
print(*[i.ljust(longest) for i in keys])
print(*[i.ljust(longest) for i in values])
Output:
A B C D E
some words of different length
Note that I harnessed fact that .keys() and .values() return key and values in same order, if no action was undertaken between them regarding given dict.

defining multiple variables to an empty list in a loop

I am trying to create and assign 10 variables, only differenciated by their index, all as empty lists within a for loop.
The ideal output would be to have agent_1 = [], agent_2 = [], agent_n = []
I know I could write this all out but thought I should be able to create a simple loop. The main issue is assigning the empty list over each iteration
for i in range(1,10):
agent_ + i = []
Why don't you use dict object with keys equal to agent_i.
dic = {}
for i in range(1,10):
dic["agent_" + str(i)] = []
// access the dic directly and iterating purpose also just iterate through the dictionary.
print dic["agent_1"]
# iteration over the dictionary
for key,value in dic.items():
print key,value
Here is the link to code snippet
This is a horrible idea. I will let the code speak for itself:
n = 10
for i in range(n):
globals()['agent_%d' % (i + 1)] = []
a = {}
for i in xrange(10):
ab = "{}_{}".format("agent", i)
a[ab] = []
print a
#OP
{'agent_0': [], 'agent_1': [], 'agent_2': [], 'agent_3': [], 'agent_4': [], 'agent_5': [], 'agent_6': [], 'agent_7': [], 'agent_8': [], 'agent_9': []}

Python: Adding integer elements of a nested list to a list

So, I have two lists whose integer elements need to be added.
nested_lst_1 = [[6],[7],[8,9]]
lst = [1,2,3]
I need to add them such that every element in the nested list, will be added to its corresponding integer in 'lst' to obtain another nested list.
nested_list_2 = [[6 + 1],[7 + 2],[8 + 3,9 + 3]]
or
nested_list_2 = [[7],[9],[11,12]]
Then, I need to use the integers from nested_list_1 and nested_list_2 as indices to extract a substring from a string.
nested_list_1 = [[6],[7],[8,9]] *obtained above*
nested_list_2 = [[7],[9],[11,12]] *obtained above*
string = 'AGTCATCGTACGATCATCGAAGCTAGCAGCATGAC'
string[6:7] = 'CG'
string[7:9] = 'GTA'
string[8:11] = 'TACG'
string[9:12] = 'ACGA'
Then, I need to create a nested list of the substrings obtained:
nested_list_substrings = [['CG'],['GTA'],['TACG','ACGA']]
Finally, I need to use these substrings as key values in a dictionary which also possesses keys of type string.
keys = ['GG', 'GTT', 'TCGG']
nested_list_substrings = [['CG'],['GTA'],['TACG','ACGA']]
DNA_mutDNA = {'GG':['CG'], 'GTT':['GTA'], 'TCGG':['TACG','ACGA']}
I understand that this is a multi-step problem, but if you could assist in any way, I really appreciate it.
Assuming you don't need the intermediate variables, you can do all this with a dictionary comprehension:
a = [[6],[7],[8,9]]
b = [1,2,3]
keys = ['GG', 'GTT', 'TCGG']
s = 'AGTCATCGTACGATCATCGAAGCTAGCAGCATGAC'
DNA_mutDNA = {k: [s[start:start+length+1] for start in starts]
for k, starts, length in zip(keys, a, b)}
You can produce the substring list directly with a nested list comprehension, nested_lst_2 isn't necessary.
nested_lst_1 = [[6],[7],[8,9]]
lst = [1,2,3]
string = 'AGTCATCGTACGATCATCGAAGCTAGCAGCATGAC'
keys = ['GG', 'GTT', 'TCGG']
substrings = [[string[v:i+v+1] for v in u] for i, u in zip(lst, nested_lst_1)]
print(substrings)
DNA_mutDNA = dict(zip(keys, substrings))
print(DNA_mutDNA)
output
[['CG'], ['GTA'], ['TACG', 'ACGA']]
{'GG': ['CG'], 'GTT': ['GTA'], 'TCGG': ['TACG', 'ACGA']}
In[2]: nested_lst_1 = [[6],[7],[8,9]]
...: lst = [1,2,3]
...: string = 'AGTCATCGTACGATCATCGAAGCTAGCAGCATGAC'
...: keys = ['GG', 'GTT', 'TCGG']
In[3]: nested_lst_2 = [[elem + b for elem in a] for a, b in zip(nested_lst_1, lst)]
In[4]: nested_list_substrings = []
...: for a, b in zip(nested_lst_1, nested_lst_2):
...: nested_list_substrings.append([string[c:d + 1] for c, d in zip(a, b)])
...:
In[5]: {k: v for k, v in zip(keys, nested_list_substrings)}
Out[5]: {'GG': ['CG'], 'GTT': ['GTA'], 'TCGG': ['TACG', 'ACGA']}
Surely not the most readable way to do it, here is a bit of functional style fun:
nested_lst_1 = [[6], [7], [8,9]]
lst = [1, 2, 3]
nested_lst_2 = list(map(
list,
map(map, map(lambda n: (lambda x: n+x), lst), nested_lst_1)))
nested_lst_2
Result looks as expected:
[[7], [9], [11, 12]]
Then:
from itertools import starmap
from operator import itemgetter
make_slices = lambda l1, l2: starmap(slice, zip(l1, map(lambda n: n+1, l2)))
string = 'AGTCATCGTACGATCATCGAAGCTAGCAGCATGAC'
get_slice = lambda s: itemgetter(s)(string)
nested_list_substrings = list(map(
lambda slices: list(map(get_slice, slices)),
starmap(make_slices, zip(nested_lst_1, nested_lst_2))))
nested_list_substrings
Result:
[['CG'], ['GTA'], ['TACG', 'ACGA']]
And finally:
keys = ['GG', 'GTT', 'TCGG']
DNA_mutDNA = dict(zip(keys, nested_list_substrings))
DNA_mutDNA
Final result:
{'GG': ['CG'], 'GTT': ['GTA'], 'TCGG': ['TACG', 'ACGA']}

search an array element in other 2d list and count sublists in python

I'm new in python,
I have a list like : A=['a','b','c']
and a list like B=[['a','c'],['a','c'],['b','b']]
i want to have a list like C=[2,1,2]
C stores occurrence of sublists that each element of A comes in B
that means 'a' is in 2 sublists
'b' is in 1 sublist
and 'c' is in 2 sublists,
how can I achieve this?
thanks
You can use sum:
a=['a','b','c']
b=[['a','c'],['a','c'],['b','b']]
final_list = [sum(i in c for c in b) for i in a]
Output:
[2, 1, 2]
You can loop over b and update a collections.Counter for each sublist, using set to remove duplicates:
from collections import Counter
a = ['a','b','c']
b = [['a','c'],['a','c'],['b','b']]
counter = Counter()
for sublist in b:
counter.update(set(sublist))
c = [counter[x] for x in a]
# result: [2, 1, 2]
You can loop and compare in both lists
a=['a','b','c']
b=[['a','c'],['a','c'],['b','b']]
result = []
for letter in a:
count = 0
for l in b:
if letter in l:
count += 1
result.append(count)
You can try dict approach :
A=['a','b','c']
B=[['a','c'],['a','c'],['b','b']]
d={}
for i in A:
for j in B:
if i in j:
if i not in d:
d[i]=1
else:
d[i]+=1
print(d)
output:
{'c': 2, 'b': 1, 'a': 2}
You can use a list comprehension with sum to construct C.
C = [sum(elem in sub for sub in B) for elem in A]
This has the same effect as using nested for loops:
C = []
for elem in A:
sum = 0
for sub in B:
sum += elem in sub
C.append(sum)
Here is a solution with collections.defaultdict.
from collections import defaultdict
a = ['a','b','c']
b = [['a','c'],['a','c'],['b','b']]
# initialise defaultdict
d = defaultdict(int)
# convert to sets for performance
a_set = set(a)
b_sets = list(map(set, b))
# loop through list of sets
for item in b_sets:
for i in item & a_set:
d[i] += 1
# retrieve counts in correct order
res = list(map(d.get, a))
print(res)
# [2, 1, 2]
Performance note
This may not matter, but the performance differential is interesting as it shows clearly the Counter overhead (4x slower).
from collections import defaultdict, Counter
a = ['a','b','c']
b = [['a','c'],['a','c'],['b','b']]
b = b*100000
def dd(a, b):
d = defaultdict(int)
a_set = set(a)
b_sets = list(map(set, b))
for item in b_sets:
for i in item & a_set:
d[i] += 1
return list(map(d.get, a))
def counter(a, b):
counter = Counter()
for sublist in b:
counter.update(set(sublist))
return [counter[x] for x in a]
assert dd(a, b) == counter(a, b)
%timeit dd(a, b) # 414 ms
%timeit counter(a, b) # 1.65 s

Categories