Store Key Value Pairs as List Comprehension - python

I have this function:
datapoints = 3
abc = ['a','b','c', ... 'z']
character = abc[:datapoints]
for n in character:
values = int(askstring("Title", "Value: ")) # 1
dat1= character.pop(0) # a
dat2 = dat1 + "," + str(values) # a,1
d = dat2.split(",") # [a,1]
data = list((d, d)) # [['a', '1']]
print(data)
unfortunately, the data gets overridden after every loop and therefore I get this:
[['a', '1'],['a', '1']]
[['b', '2'],['b', '2']]
[['c', '3'],['c', '3']]
instead of this:
[['A', 1],['B', 2]],['C', 3]]
I have tried also list(zip(d, d)), but that doesn't help at all:
[('a', 'a'),('1', '1')]
[('b', 'b'),('2', '2')]
[('c', 'c'),('3', '3')]
Thank you for any help

Your loop is overriding the values of data and d every time, you want to put data = [] at the beginning of the loop and data.append(d) in the middle of the loop. Example:
data = []
for n in character:
d = ...
data.append(d)
Your loop is popping characters from character and looping over the list. You want to do either:
for n in character:
dat1 = n
Or:
while character:
dat1 = character.pop(0)

Related

Obtaining top 2 max values from a list and finding its corresponding value from 2nd list

I am currently trying to obtain top 2 maximum values from the following list (Quant) and its corresponding value from the 2nd list (FF).
Quant = ['1', '29', '109', '2', '1', '1', '100']
FF = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
The top 2 max value in 1st list is 100 & 109 and its corresponding value in 2nd list is c & g. I tried to get the position of top values in Quant list by the following method.
a = max(Quant)
pos1 = [i for i, j in enumerate(Qu) if j == a]
Quant.remove(a)
b = max(Quant)
pos2 = [i for i, j in enumerate(Qu) if j == b]
for x, y in zip(pos1, pos2)
FC1 = FF[x]
FC2 = FF[y]
i am not sure if it is the correct way. The current Quant list does not contain duplication in max values. What if there are duplication and in that case pos1 will have 2 index values. If yes, In that i would need those 2 values from list 1 along with the subsequent value from list2.
Kindly assist me on the part.
In one line, you can do this by sorting the zipped list then unzipping only the first two items:
((FC1,FC2), (pos1,pos2)) = zip(
*sorted(zip(Quant,FF), key=lambda x:int(x[0]), reverse=True)[:2])
or if you interchange the variables, you don't even need to unzip:
((FC1,pos1), (FC2,pos2)) = sorted(zip(Quant,FF),
key=lambda x:int(x[0]), reverse=True)[:2]
>>> FC1
'109'
>>> FC2
'100'
>>> pos1
'c'
>>> pos2
'g'
This would do it, I hope you find it an elegant solution:
[*map(lambda x: FF[x], map(lambda x: Quant.index(str(x)), sorted(map(int, Quant),
reverse=True)[:2]))]
['c', 'g']
Or this:
[FF[i] for i in map(lambda x: Quant.index(str(x)), sorted(map(int, Quant),
reverse=True)[:2])]
Will the values in Quant always be strings? If you have control over it, you should make them numbers, because right now max(Quant) returns 29.
Here's one way to get what you're looking for:
Quant = ['1', '29', '109', '2', '1', '1', '100']
FF = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
quantNums = [int(n) for n in Quant]
max2, max1 = sorted(zip(quantNums, FF))[-2:]
max1 # (109, 'c')
max2 # (100, 'g')
You can achieve that using numpy,
import numpy as np
# Convert the list to numpy array
Quant = ['1', '29', '109', '2', '1', '1', '100']
Quant = np.array(Quant).astype(int)
# Get the two largest elements
ind = Quant.argsort()[-2:]
# Get the values from FF
FF = np.array(['a', 'b', 'c', 'd', 'e', 'f', 'g'])
FF[ind]

How to combine two elements of a list based on a given condition

I want to combine two elements in a list based on a given condition.
For example if I encounter the character 'a' in a list, I would like to combine it with the next element. The list:
['a', 'b', 'c', 'a', 'd']
becomes
['ab', 'c', 'ad']
Is there any quick way to do this?
One solution I have thought of is to create a new empty list and iterate through the first list. As we encounter the element 'a' in list 1, we join list1[index of a] and list1[index of a + 1] and append the result to list 2. However I wanted to know if there is any way to do it without creating a new list and copying values into it.
This does not create a new list, just modifies the existing one.
l = ['a', 'b', 'c', 'a', 'd']
for i in range(len(l)-2, -1, -1):
if l[i] == 'a':
l[i] = l[i] + l.pop(i+1)
print(l)
If you don't want to use list comprehension to create a new list (maybe because your input list is huge) you could modify the list in-place:
i=0
while i < len(l):
if l[i]=='a':
l[i] += l.pop(i+1)
i += 1
Use a list comprehension with an iterator on your list. When the current iteratee is a simply join it with the next item from the iterator using next:
l = ['a', 'b', 'c', 'a', 'd']
it = iter(l)
l[:] = [i+next(it) if i == 'a' else i for i in it]
print l
# ['ab', 'c', 'ad']
Well, if you don't want to create a new list so much, here we go:
from itertools import islice
a = list("abcdabdbac")
i = 0
for x, y in zip(a, islice(a, 1, None)):
if x == 'a':
a[i] = x + y
i += 1
elif y != 'a':
a[i] = y
i += 1
try:
del a[i:]
except:
pass
you could use itertools.groupby and group by:
letter follows a or
letter is not a
using enumerate to generate the current index, which allows to fetch the previous element from the list (creating a new list but one-liner)
import itertools
l = ['a', 'b', 'c', 'a', 'd']
print(["".join(x[1] for x in v) for _,v in itertools.groupby(enumerate(l),key=lambda t: (t[0] > 0 and l[t[0]-1]=='a') or t[1]=='a')])
result:
['ab', 'c', 'ad']
This is easy way. Mb not pythonic way.
l1 = ['a', 'b', 'c', 'a', 'd']
do_combine = False
combine_element = None
for el in l1:
if do_combine:
indx = l1.index(el)
l1[indx] = combine_element + el
do_combine = False
l1.remove(combine_element)
if el == 'a':
combine_element = el
do_combine = True
print(l1)
# ['ab', 'c', 'ad']

Reading from a file diagonally and having the diagonal characters create a list

I need to read a file containing information on different lines - for example the file may contain
12345678910
abcdefghij
zyxwvutsrq
I will then need to read the code diagonally so my list would be:
(1bx)(2cw)(3dv)
I have tried using zip and just can't figure out a way to get it to work.
EDIT
Is there anyway to also make it take into account the diagonals before the top left corner for example:
(ay)(z)
in the example file I used.
Edit 2: this is my almost complete code
with open(FileName) as diagonal :
a = diagonal.read().splitlines()
l = [a[i][i:] for i in range(len(a))]
Diaglist = [''.join(i) for i in zip(*l)]
with open(FileName) as diagonal1 :
b = diagonal1.read().splitlines()
o = [b[i][:i] for i in range(len(b))]
Diaglist1 = [''.join(i) for i in zip(*o)]
When I run the file I get the correct diagonals for the first with so from the top right to left but the second with so from the top right downwards I just get an empty list.
Do you mean:
>>> with open('file') as f:
... l = f.read().splitlines()
>>> l
['12345678910', 'abcdefghij', 'zyxwvutsrq']
>>> l = [l[0]] + [l[1][1:]] + [l[2][2:]] # remove 'a' from `l[1]` and `zy` from `l[2]`
>>> l
['12345678910', 'bcdefghij', 'xwvutsrq']
>>> list(zip(*l)) # zip them
[('1', 'b', 'x'), ('2', 'c', 'w'), ('3', 'd', 'v'), ('4', 'e', 'u'), ('5', 'f', 't'), ('6', 'g', 's'), ('7', 'h', 'r'), ('8', 'i', 'q')]
>>> [''.join(i) for i in list(zip(*l))] # also join them
['1bx', '2cw', '3dv', '4eu', '5ft', '6gs', '7hr', '8iq']
>>>
If you don't know how many lines in your file, we can use some magic code like [a[i][i:] for i in range(len(a))].
Try:
with open('file') as f:
a = f.read().splitlines()
l = [a[i][i:] for i in range(len(a))]
final_list = [''.join(i) for i in zip(*l)]
print(final_list)
As your edit, you can change a[i][i:] to a[i][:i]. Very simple:
with open('file') as f:
a = f.read().splitlines()
l = [a[i][:i] for i in range(len(a))]
final_list = [''.join(i) for i in zip(*l)][1:] # since the first element in the list will be empty (`''`), remove it.
print(final_list)
The following will work for an arbitrary number of lines of the same length, and wraps the final diagonals. This may not be what you want.
def diagonals(lines):
size = len(lines[0])
positions = [[(i + x) % size for x in range(len(lines))]
for i in range(size)]
return ["".join([lines[i][p] for i, p in enumerate(posn)])
for posn in positions]
>>> print(diagonals(['1234567891', 'abcdefghij', 'zyxwvutsrq']))
['1bx', '2cw', '3dv', '4eu', '5ft', '6gs', '7hr', '8iq', '9jz', '1ay']

Output element with the greatest value in certain position. Python

what I am trying to do here is append the element form the_list with the greatest value
in the [-1] position . i started by creating an index dictionary for the elements in the_list but i started to get lost in the logic flow.
the_list = [['a','b','c','1'],['b','c','e','4'],['d','e','f','2']]
D_indx_element = {}
D_indx_value = {}
output = []
temp = []
for i,k in zip(range(0,len(the_list)),the_list):
D_indx_element[i] = k
temp.append(int(k[-1]))
D_indx_value[i] = int(k[-1])
in the end i would like to have:
output = [['b','c','e','4']]
since 4 is greater than 1 and 2
Use max:
>>> the_list = [['a','b','c','1'],['b','c','e','4'],['d','e','f','2']]
>>> max(the_list, key=lambda x:int(x[-1]))
['b', 'c', 'e', '4']
Without lambda:
def func(x):
return int(x[-1])
max(the_list, key=func)
#['b', 'c', 'e', '4']

How to convert comma-delimited string to list in Python?

Given a string that is a sequence of several values separated by a commma:
mStr = 'A,B,C,D,E'
How do I convert the string to a list?
mList = ['A', 'B', 'C', 'D', 'E']
You can use the str.split method.
>>> my_string = 'A,B,C,D,E'
>>> my_list = my_string.split(",")
>>> print my_list
['A', 'B', 'C', 'D', 'E']
If you want to convert it to a tuple, just
>>> print tuple(my_list)
('A', 'B', 'C', 'D', 'E')
If you are looking to append to a list, try this:
>>> my_list.append('F')
>>> print my_list
['A', 'B', 'C', 'D', 'E', 'F']
In the case of integers that are included at the string, if you want to avoid casting them to int individually you can do:
mList = [int(e) if e.isdigit() else e for e in mStr.split(',')]
It is called list comprehension, and it is based on set builder notation.
ex:
>>> mStr = "1,A,B,3,4"
>>> mList = [int(e) if e.isdigit() else e for e in mStr.split(',')]
>>> mList
>>> [1,'A','B',3,4]
Consider the following in order to handle the case of an empty string:
>>> my_string = 'A,B,C,D,E'
>>> my_string.split(",") if my_string else []
['A', 'B', 'C', 'D', 'E']
>>> my_string = ""
>>> my_string.split(",") if my_string else []
[]
>>> some_string='A,B,C,D,E'
>>> new_tuple= tuple(some_string.split(','))
>>> new_tuple
('A', 'B', 'C', 'D', 'E')
You can split that string on , and directly get a list:
mStr = 'A,B,C,D,E'
list1 = mStr.split(',')
print(list1)
Output:
['A', 'B', 'C', 'D', 'E']
You can also convert it to an n-tuple:
print(tuple(list1))
Output:
('A', 'B', 'C', 'D', 'E')
You can use this function to convert comma-delimited single character strings to list-
def stringtolist(x):
mylist=[]
for i in range(0,len(x),2):
mylist.append(x[i])
return mylist
#splits string according to delimeters
'''
Let's make a function that can split a string
into list according the given delimeters.
example data: cat;dog:greff,snake/
example delimeters: ,;- /|:
'''
def string_to_splitted_array(data,delimeters):
#result list
res = []
# we will add chars into sub_str until
# reach a delimeter
sub_str = ''
for c in data: #iterate over data char by char
# if we reached a delimeter, we store the result
if c in delimeters:
# avoid empty strings
if len(sub_str)>0:
# looks like a valid string.
res.append(sub_str)
# reset sub_str to start over
sub_str = ''
else:
# c is not a deilmeter. then it is
# part of the string.
sub_str += c
# there may not be delimeter at end of data.
# if sub_str is not empty, we should att it to list.
if len(sub_str)>0:
res.append(sub_str)
# result is in res
return res
# test the function.
delimeters = ',;- /|:'
# read the csv data from console.
csv_string = input('csv string:')
#lets check if working.
splitted_array = string_to_splitted_array(csv_string,delimeters)
print(splitted_array)

Categories

Resources