Convert string of list to list - python

I have the list of strings:
['[12 9 15]','[98 12 18]','[56 45 45]']
and I want to convert it to
[[12,9,15],[98,12,18],[56,45,45]]

You can use split inside a list comprehension to do this.
As [1 2 3] is not the proper representation of a python list in a string, we can remove the brackets to get '1 2 3' which on splitting becomes ['1', '2', '3']. This can be easily converted to a integer nested list by casting it to an int using the int callable.
>>> l = ['[12 9 15]','[98 12 18]','[56 45 45]']
>>> [[int(j) for j in i[1:-1].split()] for i in l]
[[12, 9, 15], [98, 12, 18], [56, 45, 45]]
For further reading What does "list comprehension" mean? How does it work and how can I use it?

Your strings [12 9 15] aren't formatted like python lists (commas are missing). You've got a couple options depending on how robust your parser needs to be:
import ast
out_list = []
for string_list in list_of_strings:
list_repr = ','.join(string_list.split())
out_list.append(ast.literal_eval(list_repr))
This will work so long as you don't have any inner strings formatted like:
'[ 12 9, 5] (the leading space will mess it up)
I think that probably the most robust parser that I can think of is to remove the [ and ] and them parse it yourself:
out_list = []
for string_list in list_of_strings:
str_items = string_list.replace('[', '').replace(']', '')
out_list.append([int(item) for item in str_items.split()])

As long as the strings are fairly regular, this should work:
>>> x = ['[12 9 15]','[98 12 18]','[56 45 45]']
>>> x = [[int(i) for i in string.strip('[]').split()] for string in x]
>>> x
[[12, 9, 15], [98, 12, 18], [56, 45, 45]]

Use a regular expression
[map(int, re.findall('\d+', item)) for item in x]
In case it is not always well-formated.
>>> import re
>>> [map(int, re.findall('\d+', item)) for item in x]
[[12, 9, 15], [98, 12, 18], [56, 45, 45]]

The simpler the solution, the better it is for others to understand.
Well here is my solution:
list_of_strings = ['[12 9 15]','[98 12 18]','[56 45 45]']
list_of_lists = [map(int, x[1:-1].split()) for x in list_of_strings]
So I using list-comprehension here. The 'map' function returns a list. The code x[1:-1].split() will split each string on space character(s) and the each string token would then be converted to 'int' which is the function I've passed to the map function.
Need more explanation over my code?

Please check if this is helpful.
>>> x = ['[12 9 15]','[98 12 18]','[56 45 45]']
>>> print eval(str([ item.replace(" ",",") for item in x ]).replace("'", ''))
[[12, 9, 15], [98, 12, 18], [56, 45, 45]]

Related

Split a numpy array into 8-elements arrays and invert each of them

Well, I have a numpy array like that:
a=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]
My desired output is:
b=['87654321','161514131211109','2423222120191817']
For it, I need first to split "a" into arrays of 8 elements and then I have a list like that:
np.split(a) = [array([1, 2, 3, 4, 5, 6, 7, 8], dtype=int8),
array([9, 10, 11, 12, 13, 14, 15, 16], dtype=int8),
array([17, 18, 19, 20, 21, 22, 23, 24], dtype=int8)]
so, I need to invert each array into it and join the numbers to make like a list of joint numbers.
No need for numpy, though it will work for an array as well. One way:
>>> [''.join(str(c) for c in a[x:x+8][::-1]) for x in range(0, len(a), 8)]
['87654321', '161514131211109', '2423222120191817']
Try this. You reshape your data and then convert it to string elements. Loop it and append it to new list.
import numpy as np
a=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]
lst = list(np.array(a).reshape(3,8).astype("U"))
my_lst = []
for i in lst:
my_lst.append("".join(i[::-1]))
print(my_lst)
The simplest way is first to reverse the original array (or create a reversed copy), and then to split:
a = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]
acopy = a[::-1]
splitted = np.array_split(acopy, 3)
print(splitted[0]) # [24 23 22 21 20 19 18 17]
print(splitted[1]) # [16 15 14 13 12 11 10 9]
print(splitted[2]) # [8 7 6 5 4 3 2 1]
Now when lists are reversed, you can join elements of each list to make strings:
str1 = ''.join(str(x) for x in splitted[0]) # '2423222120191817'
str2 = ''.join(str(x) for x in splitted[1]) # '161514131211109'
str3 = ''.join(str(x) for x in splitted[2]) # '87654321'

Assigning numbers to given string's letters

I am currently trying to finish a project which wants encode given paragraph using given matrix. I wanted to start make a letter list:
letterlist = np.array([" ","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"])
letterlist2 = " ABCDEFGHIJKLMNOPQRSTUVWXYZ"
samplestr = "MEET ME MONDAY"
My goal is convert the letters to integer in order like A=1,B=2...Z=26 and " "=0. Then assign them to 1x3 arrays. like
But I couldn't even make a progress. First I tried make for loops to match same letter in the letter list and samplestr. Then if they are same, give the order in the letterlist as integer. But I didn't get any output.
for letter in samplestr:
for letter2 in letterlist:
if letter2==letter:
print("x") ## To see if I get any match
I don't know where did I wrong and how should I continue this. Would making dictionary make it easier to assign letters to integers? Need some advices. Thanks for your time.
The conversion to a number is done by converting the char to a ordinary number and then subtracting 64 because that is the starting ASCII-Index for 'A'
Code looks like this:
from math import ceil
samplestr = "MEET ME MONDAY"
# Pad string to be dividable by 3
samplestr = samplestr.ljust(ceil(len(samplestr)/3) * 3)
# "MEET ME MONDAY "
# Convert to number reprensentation
samplestr = [0 if c == ' ' else (ord(c)-64) for c in samplestr]
# [13, 5, 5, 20, 0, 13, 5, 0, 13, 15, 14, 4, 1, 25, 0]
# Split in chunks of 3
matrix = [samplestr[i:i+3] for i in range(0, len(samplestr), 3)]
print(matrix)
This produces the following output:
[[13, 5, 5], [20, 0, 13], [5, 0, 13], [15, 14, 4], [1, 25, 0]]
Yes, dictionary will make it easier to assign letters to integers but if your final goal is to convert the letters to integer in order like A=1, B=2...Z=26 and " "=0, then assigning indices to the letters will also do the job.
I don't have much knowledge of numpy, so I will do it simply like this:
letterlist2 = " ABCDEFGHIJKLMNOPQRSTUVWXYZ"
samplestr = "MEET ME MONDAY "
l = []
s = []
for i in samplestr:
s.append(letterlist2.index(i))
if len(s) == 3:
l.append(s)
s = []
if s != []:
l.append(s)
print(l)
Output:
[[13, 5, 5], [20, 0, 13], [5, 0, 13], [15, 14, 4], [1, 25, 0]]
Use a dictionary (with a single list comprehension) to convert the letters to numbers (would probably be the fastest) and then reshape to have 3 columns (-1 will take care of number of rows):
convert = dict(zip(letterlist, np.arange(27)))
converted = np.array([convert[char] for char in samplestr])
#[13 5 5 20 0 13 5 0 13 15 14 4 1 25]
from math import ceil
#resize to closes upper multiple of 3
converted.resize(ceil(converted.size/3)*3)
#reshape to have 3 columns
converted = converted.reshape(-1,3)
output:
[[13 5 5]
[20 0 13]
[ 5 0 13]
[15 14 4]
[ 1 25 0]]
Here is another solution with a simple dictionary mapping and list comprehensions. Note that you don't need to hardcode letters, it's in the standard library.
from string import ascii_uppercase
chars = " " + ascii_uppercase
encode = {char:"{}".format(i) for i, char in enumerate(chars)}
def str2num(s):
return [[encode[char] for char in s[i:i+3]] for i in range(0, len(s), 3)]
s = "MEET ME MONDAY"
print(str2num(s))
which returns:
[['13', '5', '5'],
['20', '0', '13'],
['5', '0', '13'],
['15', '14', '4'],
['1', '25']]

For loop resulting in wrong output

The code snippet below results in [5,7,18,23,50], why 5 is not getting removed from the resultant list?
list1 = [11, 5, 17, 18, 23, 50]
not_needed = {11, 5}
for e in list1:
if e in not_needed:
list1.remove(e)
else:
pass
print(list1)
Because you are modifying the list as it is being iterated over.
When you read the first item, it is 11 so it gets removed.
When you read the second item, it is 17, because the first item
was removed. The item 5 is now the new first item and you never get
to check it.
Because once the 11 is removed, the 5 gets skipped during iteration. This is why you never iterate over a list and remove from it at the same time.
list1 = [11, 5, 17, 18, 23, 50]
not_needed = {11, 5}
for e in not_needed:
list1.remove(e)
print(list1)
Gives:
[17, 18, 23, 50]
Use list comprehension when looping over a list and modifying it at the same time.
list1 = [x for x in list1 if not x in not_needed]
list1
[17, 18, 23, 50]
Further details on this here:
https://www.analyticsvidhya.com/blog/2016/01/python-tutorial-list-comprehension-examples/
This is because after first iteration item 11 is deleted and it goes for second index which becomes 17 in list [5,17,18,23,50]
The best way to rectify this is to take result list so that you dont have to mutate "list1"
list1 = [11, 5, 17, 18, 23, 50]
not_needed = {11, 5}
result = []
for e in list1:
if e in not_needed:
pass
else:
result.append(e)
print(result)
for loop in python runs on the indexes not on each element.
When it finds 11 and removes it from list1, list1 becomes [5, 17, 18, 23, 50] but the loop is now on second element. So it misses 5 in the list.

Random shuffle multiple lists python

I have a set of lists in Python and I want to shuffle both of them but switching elements in same positions in both lists like
a=[11 22 33 44] b = [66 77 88 99]
*do some shuffeling like [1 3 0 2]*
a=[22 44 11 33] b = [77 99 66 88]
Is this possible?
Here's a solution that uses list comprehensions:
>>> a = [11, 22, 33, 44]
>>> b = [66, 77, 88, 99]
>>> p = [1, 3, 0, 2]
>>>
>>> [a[i] for i in p]
[22, 44, 11, 33]
>>>
>>> [b[i] for i in p]
[77, 99, 66, 88]
>>>
You can use zip in concert with the random.shuffle operator:
a = [1,2,3,4] # list 1
b = ['a','b','c','d'] # list 2
c = zip(a,b) # zip them together
random.shuffle(c) # shuffle in place
c = zip(*c) # 'unzip' them
a = c[0]
b = c[1]
print a # (3, 4, 2, 1)
print b # ('c', 'd', 'b', 'a')
If you want to retain a,b as lists, then just use a=list(c[0]). If you don't want them to overwrite the original a/b then rename like a1=c[0].
Expanding upon Tom's answer, you can make the p list easily and randomize it like this:
import random
p = [x for x in range(len(a))]
random.shuffle(p)
This works for any size lists, but I'm assuming from your example that they're all equal in size.
Tom's answer:
Here's a solution that uses list comprehensions:
a = [11, 22, 33, 44]
b = [66, 77, 88, 99]
p = [1, 3, 0, 2]
[a[i] for i in p]
[22, 44, 11, 33]
[b[i] for i in p]
[77, 99, 66, 88]
a=[11,22,33,44]
order = [1,0,3,2] #give the order
new_a = [a[k] for k in order] #list comprehension that's it
You just give the order and then do list comprehension to get new list

finding top k elements in array python without heapq or sorting

I am trying to find the top k elements of a list in python without using heapq or sorting the list.
This is what I tried,
list = [20,4,67,22,445,1,34]
k = 3
newList=[]
for i in range(0,k):
newList.append(list[i])
for i in list:
mini = min(newList)
if i <= mini:
continue
else:
newList.remove(mini)
newList.append(i)
print newList
But i am getting 67,67,445. What am I doing wrong here?
The problem is apparent when you add some tracing:
>>> list = [20,4,67,22,445,1,34]
>>> k = 3
>>> newList=[]
>>>
>>> for i in range(0,k):
... newList.append(list[i])
...
>>> for i in list:
... mini = min(newList)
... if i <= mini:
... continue
... else:
... print newList
... print "Replacing {0} with {1}".format(mini, i)
... newList.remove(mini)
... newList.append(i)
... print newList
... print '-' * 20
...
[20, 4, 67]
Replacing 4 with 20
[20, 67, 20]
--------------------
[20, 67, 20]
Replacing 20 with 67
[67, 20, 67]
--------------------
[67, 20, 67]
Replacing 20 with 22
[67, 67, 22]
--------------------
[67, 67, 22]
Replacing 22 with 445
[67, 67, 445]
You already have 67 in the list when you iterate over it and add it a second time.
I would rewrite it as:
>>> numbers = [20,4,67,22,445,1,34]
>>> k = 3
>>> newList = numbers[:k]
>>>
>>> for i in numbers[k:]:
... mini = min(newList)
... if i > mini:
... print "Replacing {0} with {1}".format(mini, i)
... newList.remove(mini)
... newList.append(i)
...
Replacing 4 with 22
Replacing 20 with 445
Replacing 22 with 34
>>> print newList
[67, 445, 34]
I would not name your list list, though.
You can simply do it as:
a = [20,4,67,22,445,1,34]
k = 3
newList=[]
for i in range(k):
pos = a.index(max(a))
newList.append(a[pos])
a.pop(pos)
>>> print newList
[67, 445, 34]
you have 67 in your newlist at beginning and the 67 never pop out
The solution from hughdbrown has one bug that I noticed.
If the list has similar entries, then the result would just display one of those entries.
For example, if the list is [1, 2, 3, 4, 5, 5], the result would display [3, 4, 5] instead of [4, 5, 5]

Categories

Resources